Nativescript-angular: Android custom back navigation issue

Created on 25 Oct 2017  Â·  4Comments  Â·  Source: NativeScript/nativescript-angular

_From @Serge-SDL on October 24, 2017 19:18_

Did you verify this is a real problem by searching [Stack Overflow]

Yes! didn't find any info here, on nativescript forum or stack overflow

Tell us about the problem

When I update tns-core-modules from 3.1.1 -> 3.2.0 I get a strange behavior with back navigation: changing page with:
this.router.navigate(['/dynamic-page/cccc']);
as not the same behavior as changing page with the same code in activityBackPressedEvent listener like this:

      Application.android.on(Application.AndroidApplication.activityBackPressedEvent, (data: Application.AndroidActivityBackPressedEventData) => {
          data.cancel = true;
          this.router.navigate(['/dynamic-page/cccc']);
      });

Which platform(s) does your issue occur on?

Android

Please provide the following version numbers that your issue occurs with:

package.json file (demo project based on Hello world with updating tns-core-modules to 3.2):

  "dependencies": {
    "@angular/animations": "~4.4.5",
    "@angular/common": "~4.4.5",
    "@angular/compiler": "~4.4.5",
    "@angular/core": "~4.4.5",
    "@angular/forms": "~4.4.5",
    "@angular/http": "~4.4.5",
    "@angular/platform-browser": "~4.4.5",
    "@angular/router": "~4.4.5",
    "nativescript-angular": "~4.4.1",
    "nativescript-theme-core": "~1.0.4",
    "reflect-metadata": "~0.1.8",
    "rxjs": "~5.4.2",
    "tns-core-modules": "^3.2.0",
    "zone.js": "~0.8.2"
  },

Please tell us how to recreate the issue in as much detail as possible.

In the demo project, I have a custom page reuse strategy:

export class CustomReuseStrategy extends NSRouteReuseStrategy implements RouteReuseStrategy {
    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
        super.shouldReuseRoute(future, curr);
        return false;
    }
}

And I have a page component that listen to route param change and update an id:

import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
import { Router, ActivatedRoute, Params } from '@angular/router';

@Component({
  selector: "dynamic-page",
  template: `
  <Stacklayout>
    <Label [text]="id"></Label>
    <Button (tap)="pageChange('aaaa')" text="Page aaaa"></Button>
    <Button (tap)="pageChange('bbbb')" text="Page bbbb"></Button>
    <Placeholder #container></Placeholder>
  </Stacklayout>
  `
})
export class DynamicPageComponent implements OnInit {
  id;
  @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;

  constructor(
    private route: ActivatedRoute,
    private router: Router) {}

  ngOnInit() {
      console.log('subscribe route param change');
      this.route.params.subscribe((params: Params) => {
        console.log('change params', JSON.stringify(params['id']));
        this.id = params['id'];
      });
    }

    pageChange(page) {
      this.router.navigate(['/dynamic-page/'+ page]);
    }
}

I listen back button press on app component like this:

import { Component, AfterViewInit } from "@angular/core";
import { Router } from '@angular/router';
import * as Application from "application";

@Component({
  selector: "my-app",
  template: `<page-router-outlet></page-router-outlet>`
})
export class AppComponent implements AfterViewInit {
  constructor(private router: Router) {}

  ngAfterViewInit() {
      Application.android.on(Application.AndroidApplication.activityBackPressedEvent, (data: Application.AndroidActivityBackPressedEventData) => {
          data.cancel = true;
          this.router.navigate(['/dynamic-page/cccc']);
      });
  }
}

Problem is: When I navigate with the buttons, it works perfectly, but when I press the back button I have got a different behevior, with a half second delay to display the id in the Label. This is new with version 3.2 (in 3.1, same behavior between 2 calls).

By working on this since last week, I found also that if I add a dynamic component like this:

    updatePage() {
      this.container.clear();

      let componentFactory = this.componentFactoryResolver.resolveComponentFactory(PageComponent);
      let componentRef = this.container.createComponent(componentFactory);
      (<PageComponent>componentRef.instance).text = this.id;

      //this.changeDetectorRef.detectChanges();
    }

PageComponent is correctly displayed if I navigate from a button with route.navigate, but if I navigate from the back button listener, it displays nothing, I have to add this.changeDetectorRef.detectChanges(); to make it work.

I don't understanf why there is a difference between navigating from a simple button or from a back button listener. Does anyone have an idea? I can give a zip of my demoproject if it helps...

Thanks!
serge

_Copied from original issue: NativeScript/NativeScript#4982_

Most helpful comment

@serge-sdl could you try running the callback within a NgZone?

this.ngZone.run(() => {
    this.router.navigate(['/dynamic-page/cccc']);
});

All 4 comments

@serge-sdl could you try running the callback within a NgZone?

this.ngZone.run(() => {
    this.router.navigate(['/dynamic-page/cccc']);
});

Hi and thank you for your answer. It work! but can you explain a little why? (I don't really get it)
Thanks!

I believe it has to do with that piece of code, i.e the callback running in
a different context from Angular's ChangeDetection when it finally
evaluates. Placing it within the zone reminds Angular to act on whatever
the callback needs when its done.

On Oct 27, 2017 12:21 PM, "Serge" notifications@github.com wrote:

Hi and thank you for your answer. It work! but can you explain a little
why? (I don't really get it)
Thanks!

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/NativeScript/nativescript-angular/issues/1058#issuecomment-339945014,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AF675n697qq5L7ZuI-QkxsZVSsUMQCBWks5swbzOgaJpZM4QF0bQ
.

@jogboms Thanks that worked for me!

For anyone else new like me, you need the following.

Import
import { NgZone } from "@angular/core";

Inject
constructor(private ngZone: NgZone) { ... }

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vakrilov picture vakrilov  Â·  3Comments

pkoleva picture pkoleva  Â·  3Comments

tsonevn picture tsonevn  Â·  3Comments

bhavincb picture bhavincb  Â·  3Comments

sarvagayatri picture sarvagayatri  Â·  3Comments