2

How to stop ActivatedRoute.queryParams.subscribe to be called on back navigation?

platform(s) the issue occur on

  • iOS iOS 11 ipad mini2
  • iphone 6 plus,
  • Nativescript playground

the following version numbers:

  • tns-core-moduels 4.2.0
  • tns-ios 4.2.0
  • angular/compiler-cli 6.1.2
  • angular/router 6.1.2
  • nativescripte-angular 6.1.0

the steps to reproduce it: There are 3 page: home, entity, contact. they are root level page and using page-router-outlet

  1. In home page, go to entity page with param id = 1 on tap a button

    this.routerExtensions.navigate(['/entity'],
            {
                queryParams: {
                    id: '1'
                }
            }
        );
    
  2. In entity page, go to contact page with param id = 2 on tap another button

     this.routerExtensions.navigate(['/contact'],
            {
                queryParams: {
                    id: '2'
                }
            }
        );
    
  3. In contact page, tap the system back button on top-left to go back to entity page

expect result: In entity page, router.queryParams.subscribe should NOT be called on back navigation and show entity page without any refresh.

export class EntityComponent implements OnInit {
...
ngOnInit(): void {

    //if it's from Home page, that's OK;  
    //but how to stop it to be called on navigating back? 
    this.router.queryParams.subscribe(params => {
    console.log("EntityComponent queryParams with id : " + params.id);

    //To refresh page on regular navigating using id = 1.  
    //On back navigation, the page shouldn't be refreshed.

        });
}

actual result: this.router.queryParams.subscribe is called with param id= 2 ( the contact page id)

code: https://play.nativescript.org/?template=play-ng&id=SgrzAJ&v=9


BTW, @tsonevn suggested solution in github doesn't work, this line:

this.router.queryParams.unsubscribe();

has even compile problems in the playground. this.router.queryParams doesn't have the 'unsubscribe' method.

entity.component.ts

I would suggest unsubscribing from the this.router.queryParams when you navigate to another page and to subscribe for it again when you are entering the EntityComponent. For example:

onButtonTap(): void {
     this.router.queryParams.unsubscribe();
    console.log("Entity Button was pressed, go to contact Page with id = 2");
    this.routerExtensions.navigate(['/contact'],
        {
            queryParams: {
                id: '2'
            }
        }
    );
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Alan Yang
  • 21
  • 5

1 Answers1

0

Solution by OP.

Thanks to @tsonevn, he updated his solution in github, it works now.

New Code Demo: https://play.nativescript.org/?template=play-ng&id=SgrzAJ&v=13

Basically, this one line works on tapping a button to leave the page.

this.subs.unsubscribe();

However, real case may be more complex. Eg: there are 3 child components in entity page, everyone has a button to navigate to contact page. we need to pass 'this.subs' to child components, and to maintain 3 places to do 'unsubscribe()'.

How to do it in one place?

Router Guard 'CanDeactivate' is a good way to inject it.

The steps:

  1. create a can-deactivate-guard.ts, call 'component.unsubscribeQueryParams' method on page deactivate

    export class CanDeactivateGuard implements CanDeactivate<any> {
    canDeactivate(component: any, route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        if (component.unsubscribeQueryParams()) {
            return true;
        } else {
            return false;
        }
    }
    

    }

  2. put it in 'entity-routing.module.ts'

    const routes: Routes = [
    { path: "entity", component: EntityComponent, canDeactivate: [CanDeactivateGuard] }];
    
  3. implement the method 'unsubscribeQueryParams in 'entity.component.ts'

    unsubscribeQueryParams() {
    if (this.subscription) {
        //be called by CanDeactivateGuard.canDeactivate() on leaving this page.
        this.subscription.unsubscribe();    
    }       
    return true; }
    
  4. register 'can-deactivate-guard' into 'app.module.'

Another reason to use 'CanDeactivate' is with page-router-outlet, when going forward, current page 'ngOnDestroy' method won't be called, so put this.subscription.unsubscribe() in 'ngOnDestroy' doesn't work.

From Nativescript document:

With page-router-outlet when you navigate forward, the current page and views are saved in the native navigation stack. The corresponding component is not destroyed. It is cached.

For more info, please check 'component lifecycle when using page-router-outlet and router-outlet'

This problem is resolved.

Related links:

Cœur
  • 37,241
  • 25
  • 195
  • 267