Angular *ngIf updating after clicking on page or alt+tab (refocusing) - html

I have a strange bug on an angular project,these are the fragments of the code
#Injectable()
export class FirebaseMessagingService {
public tokenReceivedEmitter: any = new EventEmitter();
public messageReceivedEmitter: any = new EventEmitter();
constructor(
private angularFireMessaging: AngularFireMessaging) {
this.angularFireMessaging.messaging.subscribe(
(messaging) => {
messaging.onMessage = messaging.onMessage.bind(messaging);
messaging.onTokenRefresh = messaging.onTokenRefresh.bind(messaging);
}
);
}
/**
* request permission for notification from firebase cloud messaging
*
* #param userId userId
*/
requestPermission(userId) {
this.angularFireMessaging.requestToken.subscribe(
(token) => {
this.tokenReceivedEmitter.emit({status: true, result: token});
},
(err) => {
this.tokenReceivedEmitter.emit({status: false, result: err});
}
);
}
/**
* hook method when new notification received in foreground
*/
receiveMessage() {
this.angularFireMessaging.messages.subscribe(
(payload) => {
this.messageReceivedEmitter.emit(payload);
});
}
So this was the firebase messaging service which emit token receiving events and when a push notification is received.
Now in the component
ngOnInit(){
// Subscribing to firebase token receive
this.firebaseTokenSubscription = this.messagingService.tokenReceivedEmitter.subscribe(
(message) => {
if (message.status) {
const token = message.result;
this.sendNotificationToken(token);
} else {
this.snackBar.open(message.result, this.translate.instant('CLOSE')
{duration:3000});
}
}
);
}
And also I have enable/disable button in the component, here are the html parts of that code
<div *ngIf="user && !user.webPushEnabled"
class="user-verification fx-all-100 layout-all-row-wrap">
<div class="fx-gtSm-48 fx-ltMd-100 layout-all-col-nowrap">
<p>{{"EXCHANGE.PROFILE.ENABLE_DISABLE_NOTIFICATION" | translate}}</p>
</div>
<div class="fx-gtSm-48 fx-ltMd-100 offset-gtSm-4 align-all-fxEnd-fxStr">
<button mat-raised-button class="button-auth button-main-shadow"
(click)="updateNotificationStatus(true)">
{{"EXCHANGE.PROFILE.ENABLE_NOTIFICATIONS_BUTTON" | translate}}
</button>
</div>
</div>
<div *ngIf="user && user.webPushEnabled"
class="user-verification fx-all-100 layout-all-row-wrap">
<div class="fx-gtSm-48 fx-ltMd-100 layout-all-col-nowrap">
<p>{{"EXCHANGE.PROFILE.ENABLE_DISABLE_NOTIFICATION" | translate}}</p>
</div>
<div class="fx-gtSm-48 fx-ltMd-100 offset-gtSm-4 align-all-fxEnd-fxStr">
<button mat-raised-button class="del-api-key-btn button-main-shadow"
(click)="updateNotificationStatus(false)">
{{"EXCHANGE.PROFILE.DISABLE_NOTIFICATIONS_BUTTON" | translate}}
</button>
</div>
</div>
And obviously I have
updateNotificationStatus(on: boolean) {
if (on) {
this.messagingService.requestPermission(this.user.userId);
} else {
this.userService.updateNotificationStatus(null, false).subscribe(
(result) => {
this.user.webPushEnabled = false;
},
(error) => {
this.snackBar.open(error, this.translate.instant('CLOSE'), {duration: 3000});
}
);
}
}
sendNotificationToken(token) {
this.userService.updateNotificationStatus(token, true).subscribe(
(result) => {
debugger;
this.user.webPushEnabled = true;
},
(error) => {
this.snackBar.open(error, this.translate.instant('CLOSE'), {duration: 3000});
}
);
}
The problem is that when I enable push notifications it only updates html when page is reloaded or refocused(alt+tab or clicking on page with mouse). It also works fine when webpage is loaded at first time.
Pleas help any suggestions or ideas may help.

The problem was that firebase was requesting user token outside Angular's view thread, so I had to update the model in angular's view thread.
this.ngZone.run(() =>{
this.user.webPushEnabled = true;
})
It helped me out.

Related

how to pass data from dialog box in Angular

Right now In my Edit page a user can delete section and subsection but I'm thinking about adding confirmation dialog so that a user will not accidentally delete either of them.
I'm not really sure how I can pass the data between confirmation dialog component and Edit Page component.
The project is not gonna run on on Stackblitz but I have uploaded those two component in here https://stackblitz.com/edit/angular-ivy-ztepf6?file=Edit Component/EditComponent.ts
so I will be really appreciated if anybody can check it out and able to help me. thanks
Edit Component.TS
this is how I open Comfirmation Dialog
openSection() {
let dialogRef = this.dialog.open(ConfirmDialogComponent, {
data: {
isSection: true, isSubsection: false
},
}
);
}
openSubsection(){
this.dialog.open(ConfirmDialogComponent, {
data: {
isSubsection: true, isSection: false
},
});
}
//This is how I'm deleting right now without confirmation Dialog
delete(sec) {
if (this.isSection) {
this.HelpService.deleteHelpSection(sec.id).subscribe(() => {
const index = this.mappedSections.findIndex((value) => value.id == sec.id);
this.mappedSections = this.mappedSections.filter(section => section.id != sec.id)
if (~index) {
this.HelpService.deleteHelpSubsection(sec.id).subscribe(() => {
this.mappedSections = this.mappedSections.filter(section => section.id != sec.id);
})
}
})
} if (this.isSubsection) {
this.HelpService.deleteHelpSubsection(sec.id).subscribe(() => {
const index = this.mappedSections.findIndex((value) => value.id == sec.parentId);
if (~index) {
this.mappedSections[index].subSections = this.mappedSections[index].subSections.filter((subsection) => subsection.id != sec.id)
}
})
}
}
subscribe for the result from the modal.
openSection() {
let dialogRef = this.dialog.open(ConfirmDialogComponent, {
data: {
isSection: true, isSubsection: false
},
});
dialogRef.afterClosed().subscribe(result => {
console.log('The dialog was closed', result);
if(result){
this.delete(sec)
}
});
}
from the modal component pass the data
<button mat-raised-button (click)="closeDialog()">Close</button>
constructor(
public dialogRef: MatDialogRef<ConfirmDialogComponent>
) {}
closeDialog() {
this.dialogRef.close(true);
}
check this working sample
https://stackblitz.com/edit/angular-pd7vt6?file=src/app/dialog-elements-example.ts

On button click clear displayed text and call another function in VueJs

I'm fairly new to web development and vue.js.
I have an app where I enter an Id in and on button(search) click it is calling a method. This method makes an axios call to the controller and retrieves data as an object.
This data is displayed in tag (not sure if this approach is correct).
After this data is displayed, when the second time I enter another Id in the field and hit the button, it still displays the old text till it fetches the new data. Once new data is retrieved, it displays the new one.
I want to clear this data everytime I hit the button for search as well as call the vue function to fetch data.
I have tried clearing the data at the beginning of the vue function call but that didn't work.
<input type="text" placeholder="Enter the ID" v-model="mId" />
<button type="button" class="searchgray" v-on:click="SubmitId">Search</button>
<h4 style="display: inline">ID: {{queryData.Id}}</h4>
<strong>Device Status: </strong><span>{{queryData.deviceStatus}}</span>
<script>
export default {
components: {
'slider': Slider,
Slide
},
props:['showMod'],
data() {
return {
mId '',
queryData: {},
}
},
methods: {
SubmitId: function () {
this.queryData = {}
axios.get('/Home/SearchId?Id=' + this.mId)
.then(response => response.data).then(data => {
this.queryData = data
}).catch(err => {
this.queryData = {}
this.mId = ''
alert(`No records found anywhere for the given mId`)
});
}
}
</script>
So in the above code, when I hit the Search button, it calls the SubmitId function and returns queryData. Now when I enter a new mId in input field and hit serach button it continues to display the querydata associated with the old mId till the fetching of data is completed and new query data for the new mId is returned.
I was looking for a way to clear the screen text everytime I hit the button. So I also tried doing queryData={} before the axios call, but it didn't help.
Help appreciated.
new Vue({
el: '#app',
props: [
'showMod'
],
data() {
return {
mId: '',
queryData: {}
}
},
methods: {
async SubmitId () {
const axiosRequest = () => new Promise((resolve, reject) => {
const obj = {
Id: Math.random(),
deviceStatus: Math.random()
}
setTimeout(() => {
resolve(obj)
// reject('Not Found')
}, 2000)
})
try {
this.queryData = {}
this.queryData = await axiosRequest()
} catch (err) {
this.mId = ''
alert('No records found anywhere for the given mId')
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input
v-model="mId"
type="text"
placeholder="Enter the ID"
/>
<button
v-on:click="SubmitId"
type="button"
class="searchgray"
>
Search
</button>
</br>
<h4 style="display: inline">
ID: {{ queryData.Id }}
</h4>
</br>
<strong>Device Status: </strong>
<span>{{ queryData.deviceStatus }}</span>
</div>

Firebase not logging user out

I took the logout function from Firebase to logout a user that logs in. I can properly log in but I clearly cannot log out. I have tested this out many times but the log out function simply does not work. Any and all help would be much appreciated. The following is my code:
export class AuthService {
private user: Observable<firebase.User>;
private userDetails: firebase.User = null;
constructor(private _firebaseAuth: AngularFireAuth, private router: Router) {
this.user = _firebaseAuth.authState;
this.user.subscribe(
(user) => {
if (user) {
this.userDetails = user;
console.log(this.userDetails);
}
else {
this.userDetails = null;
}
}
);
}
signInWithGoogle() {
return this._firebaseAuth.auth.signInWithRedirect(
new firebase.auth.GoogleAuthProvider()
)
}
signup(email: string, password: string) {
this._firebaseAuth.auth.createUserWithEmailAndPassword(email, password)
.then(value => {
console.log('Success!', value);
})
.catch(err => {
console.log('Something went wrong:',err.message);
});
}
login(email: string, password: string) {
this._firebaseAuth.auth.signInWithEmailAndPassword(email, password)
.then(value => {
console.log('Nice, it worked!');
})
.catch(err => {
console.log('Something went wrong:',err.message);
});
}
isLoggedIn() {
if (this.userDetails == null ) {
return false;
} else {
return true;
}
}
directToNext() {
if (this.isLoggedIn){
this.router.navigate(['/or-items/1']);
}
}
logout() {
this._firebaseAuth.auth.signOut()
.then((res) => this.router.navigate(['/']));
}
}
Then in the HTML:
<script>
import {AuthService} from' ./../AuthService';
function logout() {
this.authService.logout();
}
function isLoggedIn() {
this.authService.isLoggedIn();
}
</script>
<span>
<button mat-raised-button color="basic" (click)="logout()">
logout
</button>
</span>
I know that the user is not correctly being logged out because the firebase console indicates that the user is still logged in.
Qari, AFAIK the Firebase console does not indicate whether the user is logged in or not. I think what it shows is the last login date.
At least on the Android Firebase SDK, when one requests a signout, there is a callback that can be used to indicate whether the call was successful. To be doubly sure, one can get the current user info again and verify that there is no current user. You may want to try along similar lines.

Angular, File not uploaded to Firebase Storage

I'm trying to make an upload function for uploading file/image to my firebase database storage. I have already paste the correct API key in the environment.ts and import it to app.module.ts like AngularFireModule.initializeApp(environment.firebaseConfiguration, 'app-root'). I made the push string properties function and upload file function separately. The other properties like name and description are pushed correctly into my Firebase real-time database but the file is not uploaded to the storage so i also cant obtain the url.
//product.ts
export class Product {
$prdKey: string;
prdName: string;
prdImage ? : File;
imageURL ? : any;
prdDescription: string;
constructor(prdImage: File) {
this.prdImage = prdImage;
}
}
//product.service.ts
Product: any;
selectedProduct: Product = new Product(this.Product);
currentFileUpload: Product;
insertProduct(Product: Product) {
this.productList.push({
prdName: Product.prdName,
prdDescription: Product.prdDescription
});
}
private basePath = '/';
pushFileToStorage(Product: Product) {
const storageRef = firebase.storage().ref();
const uploadTask = storageRef.child(`${this.basePath}/${Product.prdImage.name}`).put(Product.prdImage);
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
(snapshot) => {
// in progress
const snap = snapshot as firebase.storage.UploadTaskSnapshot
},
(error) => {
// fail
console.log(error)
},
() => {
// success
Product.imageURL = uploadTask.snapshot.downloadURL
Product.prdName = Product.prdImage.name
this.saveFileData(Product)
}
);
}
private saveFileData(Product: Product) {
this.firebase.list(`${this.basePath}/`).push(Product);
}
//product.component.ts
onSubmit(form: NgForm) {
if (form.value.$prdKey == null) {
this.ProductService.insertProduct(this.ProductService.selectedProduct);
} else {
this.ProductService.updateProduct(this.ProductService.selectedProduct);
}
}
upload() {
const file = this.ProductService.selectedProduct.prdImage
this.ProductService.currentFileUpload = new Product(file);
}
selectFile(event) {
this.ProductService.selectedProduct = event.target.files;
}
<!--product.component.html-->
<form #productForm="ngForm" (ngSubmit)="onSubmit(productForm); upload()">
<!--skip name and descrioption input-->
<label>Upload an Image</label>
<input type="file" class="form-control">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Can anyone help me solve this? Please let me know of more snippets are needed. Thank you in advance.

React function is not defined

I am trying to create a react component with imported data from Google API. I can see the code is working in the console.log but when I try to use that code in React render method, I am not getting anything. When I move my function inside the class it comes up as the function not defined. I cannot understand why?
function handleTouchTap() {
console.log('CHIP selected');
authorize();
}
function handleAccounts(response) {
console.log(response.result.username);
var username = response.result.username
console.log(username);
}
function authorize(event) {
var useImmidiate = event ? false : true;
var authData = {
client_id: CLIENT_ID,
scope: SCOPES,
immidiate: useImmidiate
};
gapi.auth.authorize(authData, function (response) {
gapi.client.load('analytics', 'v3').then(function () {
console.log(response);
gapi.client.analytics.management.accounts.list().then(handleAccounts);
});
});
}
class Chips extends React.Component {
render() {
return (
<div style={styles.wrapper}>
<Chip
onTouchTap={handleTouchTap}
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">perm_identity</FontIcon>} />
Login
</Chip>
<Chip
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">account_circle</FontIcon>} />
{this.username}
</Chip>
</div>
);
}
}
In most cases, when you want to render something that might change, you want to add it to the state. That way when you call setState the component knows it needs to rerender and show the changes.
Here I added the functions as component methods, so that you can call this.setState on the result. Ideally you would probably do this with redux and use actions but this will work as a self contained component.
class Chips extends React.Component {
handleTouchTap = () => {
console.log('CHIP selected');
this.authorize();
}
handleAccounts = (response) => {
var username = response.result.username;
this.setState({
username
});
}
authorize = (event) => {
var useImmidiate = event ? false : true;
var authData = {
client_id: CLIENT_ID,
scope: SCOPES,
immidiate: useImmidiate
};
gapi.auth.authorize(authData, (response) => {
gapi.client.load('analytics', 'v3').then(() => {
console.log(response);
gapi.client.analytics.management.accounts.list()
.then(this.handleAccounts);
});
});
}
render() {
return (
<div style={styles.wrapper}>
<Chip
onTouchTap={this.handleTouchTap}
style={styles.chip}>
<Avatar icon={<FontIcon className="material-icons">perm_identity</FontIcon>} />
Login
</Chip>
<Chip
style={styles.chip} >
<Avatar icon={<FontIcon className="material-icons">account_circle</FontIcon>} />
{this.state.username}
</Chip>
</div>
);
}
}