nativescript-local-notifications icon indicating copy to clipboard operation
nativescript-local-notifications copied to clipboard

Navigating to a route after tapping a notification

Open joey0xx opened this issue 6 years ago • 8 comments

Is there a way I can make the app launch a specific route other than the home after I tap a notification? Or navigate to a route after I tap the notifcation?

im doing this to register the callback for tapping a notification:

ngOnInit() {
        LocalNotifications.addOnMessageReceivedCallback((notification) => {
          
            this.routerExtension.navigate(["/details", notification.id]);
        })
    }

But i get this error: Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?

I tried wrapping it around ngZone.run() but I still get the same error:

ngOnInit() {
        LocalNotifications.addOnMessageReceivedCallback((notification) => {

             this._zone.run(() => {
                 this.routerExtension.navigate(["/details", notification.id]);
             })
        })
    }

joey0xx avatar Jan 14 '19 23:01 joey0xx

@joey0xx see this thread where it is suggested to use the launch event to navigate (when notification is received)

NickIliev avatar Jan 15 '19 07:01 NickIliev

@NickIliev Tried using the launch and resume event like this in the home component:

private _notificationId = 0
ngOnInit() { 
   
        LocalNotifications.addOnMessageReceivedCallback((notification) => {
            this._notificationId = notification.id;
            
        })
        .then(() => {
            
            app.on("launch", () => {
                if(this._notificationId > 0){
                    this.navigateToDetails();
                }
            }); 
            app.on("resume", () => {
                if(this._notificationId > 0) {
                    this.navigateToDetails();
                }
            });
        });
    }
    public navigateToDetails() {
        setTimeout(() => {
            this._routerExtensions.navigate(["/details", 0, this._notificationId], {
                transition: {
                    name: "slideTop",
                }
            });
        }, 10000)
    }

But i still get the same error. I dont get the error when wrapping it in NgZone.run() and it looks like it calls .navigate() but it never actually goes into the view.

joey0xx avatar Jan 15 '19 22:01 joey0xx

I'm facing the same issue, any update on this?

JDW-Syscom avatar May 20 '19 09:05 JDW-Syscom

If this is an issue on Android only, try adding this launchMode to <activity android:launchMode="singleTask" in AndroidManifest.xml.

EddyVerbruggen avatar May 20 '19 11:05 EddyVerbruggen

That's not working, if it's any help, I have the firebase plugin as well and it is working with firebase notifications

JDW-Syscom avatar May 20 '19 11:05 JDW-Syscom

Oh also a thing I noticed is when you did the navigation; while the page you wanted is not seen, pressing the back button on android briefly shows the page you wanted to navigate to and then goes back to the original page.

JDW-Syscom avatar Jun 18 '19 08:06 JDW-Syscom

I had a similar issue trying to navigate when receiving a local notification, and the reason the navigation was not working was that the callback from the plugin is running outside of Angular's context.

Instead of fiddling with NgZone, I added a simple service exposing a state that indicates if a local notification has been received:

@Injectable()
export class LocalNotificationsService {
    private _state: BehaviorSubject<boolean>;
    constructor() {
        this._state = new BehaviorSubject<boolean>(false);
        LocalNotifications.addOnMessageReceivedCallback(
            (notification: ReceivedNotification) => {
                this.setLocalNotificationPending(true);
            }
        ).catch(
            function() {
              console.log('LocalNotificationsService - unable to add  local notifcations listener');
            }
        );
    }
    public get state(): Observable<boolean> {
        return this._state.asObservable();
    }
    public setLocalNotificationPending(isPending: boolean) {
        this._state.next(isPending);
    }
}

The service is injected in the constructor of app.component in order to set up the callback and can be used in any component from where you want to perform the navigation. For this to work properly, I am setting up the subscription in ngOnInit:

            this.localNotificationService.state.subscribe(y => {
                if (y) {
                    this.doNavigateToReminders = true;
                }
            })

and just set a local variable to indicate that a new state is received. In order for the navigation to be performed properly, you need to initiate it from an Angular lifecycle hook, but since they are not directly connected to the NativeScript lifecycle events of page, I had use a timeout in ngAfterViewInit to ensure the local notifications callback is done and has updated the service before doing the navigation:

    ngAfterViewInit(): void {
        setTimeout(() => {
            if (this.doNavigateToReminders) {
                this.routerExtension.navigate(['/myremindercomponent'], {
                    relativeTo: this.activatedRoute,
                    clearHistory: true
                });
            }
        }, 1000);
    }

This can probably be simplified to be initiated in the subscription part of ngOnInit but depending on the complexity of the view / component where you use this, it is safer to postpone it. Also, if you need to know the ID of the local notification, you can put that into the BehaviorSubject/ state instead of just a boolean.

timdoege avatar Jul 05 '19 12:07 timdoege

Had the same issue and was able to make it work with NgZone.

setLocalNotificationsCallback() {
    LocalNotifications.addOnMessageReceivedCallback(notification => this.ngZone.run(() => {
        console.log('NOTIFICATION TAPPED', notification)
        this.router.navigate(['main'])
    })).then(() => {
        console.log('NOTIFICATIONS CALLBACK ADDED')
    }).catch(err => {
        console.log('ERROR ADDING NOTIFICATIONS CALLBACK', err)
    })
}

Add the function to app.component.ts and invoke it in ngOnInit.

I'm not 100% sure if this is something that can be corrected. Since the library is made to work with any NS platform, it will run outside Angular's zone, unless it is specifically redesigned for Angular.

Angular 7.2.15 Core 5.4.3 local-notifications 3.2.2

danielnitu avatar Aug 01 '19 10:08 danielnitu