I need to handle push notifications and I am using onesignal for it.
Currently I am handling push notifications in my home screen and I am using react-navigation.
componentDidMount() {
OneSignal.addEventListener('received', this.onReceived);
OneSignal.addEventListener('opened', this.onOpened);
}
componentWillUnmount() {
// OneSignal.removeEventListener('received');
// OneSignal.removeEventListener('opened');
}
onReceived(notification) {
console.log('Notification received: ', notification);
}
onOpened = (data) => {
const { notification: { payload } } = data;
if (payload.additionalData) {
if (payload.additionalData.params) {
this.props.navigation.navigate({
routeName: payload.additionalData.route,
params: payload.additionalData.params,
key: payload.notificationID
});
}
}
}
With this code I am able to navigate to a route specified in the data packet of notifications.
Now the problem I face is, I have a screen and I want to refresh my page, for example call getData(); of that component.
With this approach I am able to navigate to that screen and if I get the notification while I am on that screen. with the help of key, I can navigate to that screen.
Lets say I am going to OrderDetail screen and when I get the notification, It navigates to Order Detail,
Home Screen --> Order Detail
and now If I am inside OrderDetail and if I get the notification, It would be
Home Screen ---> Order Detail ---> Order Detail
...and so on'
How can I handle push notifications in this case?
Possibly... handle the push notification differently on Home and Detail pages.
Say,on Home page, listen to notification when didFocus, and remove the listener when willBlur. So the handler will action only when a user is on Home. And navigate (route) to "Detail" in the notification handler of Home page.
Likewise, on Detail page, listen to notification when didFocus, and remove the listener when willBlur. While the handler simply updates the content when notification is received.
---edit---
Home:
constructor() {
this.props.navigation.addListener(
'willBlur',() => {
OneSignal.removeEventListener('received');
OneSignal.removeEventListener('opened');
}
);
this.props.navigation.addListener(
'didFocus',() => {
OneSignal.addEventListener('received');
OneSignal.addEventListener('opened');
}
);
}
// handler implementation is the same
Detail:
//same lifecycle implementation
// but different handler
onOpened = (data) => {
const { notification: { payload } } = data;
if (payload.additionalData) {
if (payload.additionalData.params) {
this.setState(paramsUsedByDetail: payload.additionalData.params);
}
}
Related
i am using Vuex and Firebase Authentication. I got stuck when reload the page. firebase.auth().onAuthStateChanged take time to response. But i need at the same time when reload the page. I have seen many tutorials in internet, most of them is router guard, but that i don’t want. I have some route where the user has login, then can navigate to this route.
App.vue where i am applying.
created () {
firebase.auth().onAuthStateChanged(async user =>{
if (user){
await this.$store.dispatch('autoSignIn',user)
}
})
}
Here is my vuex action theat trigger when page reload to auto sign in if a user was logged before reload the page.
autoSignIn ({commit}, payload) {
commit('setUser',{email:payload.email, userId:payload.uid})
}
This is my getter
isAuthenticated:state => {
return state.user !== null && state.user !== undefined ? state.user : null
}
Here is where i am calling my getter isAuthenticated.
getEventsByUser({getters,commit}){
let data = [];
firebase.database().ref('usuario/' + getters.isAuthenticated.userId + '/eventos/')
.on("value", eventos =>{
eventos.forEach(evento =>{
data.push({"id":evento.key, ...evento.val()})
});
commit('setEventsByUser',data)
})
},
And this is the component which dispatch the action
<template>
<div>
<div v-for="(event,id) in getEventsByUser" :key="id">
{{event}}
</div>
</div>
</template>
<script>
export default {
name: "MyEvents",
computed:{
getEventsByUser(){
return this.$store.getters.getEventsByUser;
},
},
mounted() {
this.$store.dispatch('getEventsByUser')
},
}
Here is the error when i reload the page
When the page loads, Firebase checks whether the ID token that is stored for the user is still valid. This requires that it calls the server, so it may take a moment. During this check the user will be null, so your code needs to handle that everywhere.
In your onAuthStateChanged handler you handle this correctly with:
firebase.auth().onAuthStateChanged(async user =>{
if (user){
But then in getEventsByUser you assume there is a user, which (as shown by the error message) is not true. So you'll want to add a check there, to see if there's a user, before attaching the listener to the database:
getEventsByUser({getters,commit}){
let data = [];
if (getters.isAuthenticated) {
firebase.database().ref('usuario/' + getters.isAuthenticated.userId + '/eventos/')
...
Suppose I have pageA where I listen for a firebase document changes
export default {
mounted() {
this.$f7ready(() => {
this.userChanges();
})
},
methods: {
userChanges() {
Firebase.database().ref('users/1').on('value', (resp) => {
console.log('use data has changed');
});
}
}
}
Then I go to pageB using this..$f7.views.current.router.navigate('/pageB/')
If on pageB I make changes to the /users/1 firebase route I see this ,message in the console: use data has changed, even though I'm on a different page.
Any way to avoid this behavior, maybe unload the page somehow?
I tried to stop the listener before navigating away from pageA using Firebase.off() but that seems to break a few other things.
Are you properly removing the listener for that specific database reference? You'll have to save the referenced path on a dedicated variable to do so:
let userRef
export default {
mounted() {
this.$f7ready(() => {
this.userChanges();
})
},
methods: {
userChanges() {
userRef = Firebase.database().ref('users/1')
userRef.on('value', (resp) => {
console.log('use data has changed');
});
},
detachListener() {
userRef.off('value')
}
}
}
That way you only detach the listener for that specific reference. Calling it on the parent, would remove all listeners as the documentation specifies:
You can remove a single listener by passing it as a parameter to
off(). Calling off() on the location with no arguments removes all
listeners at that location.
More on that topic here: https://firebase.google.com/docs/database/web/read-and-write#detach_listeners
I am using a global provider to open pages by passing the navigation controller from the page to the provider method. Is there any other way to do this better?
Main objective is not to repeat my self. Open page method I use in the globalProvider.ts is as follows. currentActive page is stored in a variable of the provider in case user logins to the app he will be redirected to the last active page (currentActive)
globalProvider.ts
openPage(navCtrl, page, params, setActive = true) {
this.showLoading();
if (setActive) {
this.currentActive = { root: page, params: params };
} else {
this.currentActive = { root: 'HomePage', params: null };
}
navCtrl.setRoot(page, params).then(res => {
if (!res) {
this.showError('Please login to view page!');
navCtrl.setRoot('LoginPage', {
activePage: this.currentActive.root
}).then(res => {
this.hideLoading();
}).catch(err => {
this.hideLoading();
});
}
this.hideLoading();
}).catch(error => {
this.hideLoading();
});
}
I don't think there is anything bad with this practice. I also do similar logic to avoid repeating the show loading and hide loading logic in every page.
However I also keep one more parameter, to help me decide if the page should be set as root or should be pushed on current stack.
This also helps me to track page views for analytics from a central place.
I have a little bit of a problem with the angular navigator 2
I'm in my detail projects page and I have a component that is in my detail page that will show me the next project.
So in my component I recall the same page which is' /projects/id
when I click in the navigation bar it changes the id well but the content does not change and I do not understand why because I make a router. navigate of my page.
my init controller projectDetail
ngOnInit() {
this.nextProjectId = this.activedRoute.snapshot.queryParams.nextProject;
const id = this.activedRoute.snapshot.params.id
this.projectsService.projectsAll().then( (projects) => {
if (projects[this.nextProjectId]) {
this.nextProject = projects[this.nextProjectId];
} else {
this.nextProject = projects[0];
}
});
this.projectsService.projectFind(id).then( project => this.project = project);
}
my function navigate in component nextProject
nextProjectDetail(id, nextProject) {
const next = parseInt(nextProject, 0) + 1
this.router.navigate(['projects/', id], { queryParams: {nextProject: next }}).then(
function(){
console.log('navigate success');
},
function(){
console.log('navigate failure');
}
);
}
I even tried to use this function in the init of detail projects to see when the url changes but it doesn't work.
this.params.subscribe(params => {
console.log("dfsd");
});
there is another way to refresh the same page in a component on the same page?
thanks
I have two forms, one is called profile, the other is settings. I'm using introjs to have a guided tour through these two forms. If I only move forward through the tour using the introjs 'Next Step' button there are no issues (first image). But, if I use the browser back or forward button, my forms look like the second image.
Code on profile page that utilize introjs:
runTour() {
if (this.state.showTour === true) {
const tourObj = {
userId: Meteor.userId(),
page: 'profile',
};
introJs.introJs().setOption('doneLabel', 'Next step').start().oncomplete(()
=> {
changeIntroTour.call(tourObj);
browserHistory.push('/user/settings');
})
.onexit(() => {
changeIntroTour.call(tourObj);
});
}
}
componentWillReceiveProps(nextProps) {
this.existingSettings(nextProps);
if (nextProps.intro.length > 0) {
this.setState({
showTour: nextProps.intro[0].profileTour,
}, () => {
this.runTour();
});
}
}
The issue was I was not calling introJs.exit() on componentWillUnmount. This was keeping my instance of introJs running from one component to the next which caused the bug.