Search code examples
angularangular-changedetectionzonejs

Implementing a zonejs-less angular 8 project


I was migrating my angular project to angular 8 and came across these two articles :

I'm now interested in implementing having a project without zonejs.

I ran npm remove zone.js, then I removed import 'zone.js/dist/zone'; in polyfill.js and then I added , {ngZone: 'noop'} to my bootstrapModule call in my main.ts.

And whith that my app ran.

but of course now I should manually add the points where change detection are required and this is where these guides fail woefully. perhaps they are outdated (published in 2018 and 2017 respectively, which is only 1-2 years ago).

the methods they (and the other google hits you can get on .tick()) reference classes that don't exist or classes that do exist but don't have .tick().

error message : property 'tick' does not exist on type 'typeof ApplicationRef'

What's a real world example for angular 8-9, es6, ECMAScript, type implementation of manual change detection?

For example right now I'm missing one on my landing page which is supposed to redirect after token reception :

  ngOnInit() {
    this.loading = true;
    // reset login status
    if (this.window.navigator.userAgent != 'fakeAgent') {
      this.tryConnect();
      // Maybe tigger changedetect here?
    }
  }

  tryConnect(withLogout?: boolean) {
    this.error = '';
    this.loading = true;
    let uid = $('input#uid');
    if (!this.authenticationService.isOAuth && uid && uid.val()) {
      const data = {...};

      this.http.post(AppGlobal.API_URL + 'auth/tokens', data).subscribe(
        res => {
          // console.log(res);
          // Maybe tigger changedetect here?
          this.authenticationService.setToken(res.json());
          this.autologin();
        },
        err => {
          // console.log(err);
          this.authenticationService.setToken('unknown');
          this.autologin();
        }
      );
    }
  }

  autologin() {
    this.authenticationService.autologin().subscribe(
      result => {
        this.success = 'Connected';
        this.currentUser = this.authenticationService.getCurrentUser();
        let afterlogin = localStorage.getItem('afterlogin');
        let afterloginparams: any = JSON.parse(
          localStorage.getItem('afterloginparams')
        );
        if (!afterloginparams) {
          afterloginparams = {};
        }
        localStorage.removeItem('afterlogin');
        localStorage.removeItem('afterloginparams');
        if (afterlogin) {
          this.router.navigate([afterlogin], {queryParams: afterloginparams});
        } else {
          this.router.navigate(['/']);
        }
        // OR TRIGGER CHANGE DETECTION HERE ?
      },
      error => {
        let afterlogin = localStorage.getItem('afterlogin');
        let afterloginparams: any = JSON.parse(
          localStorage.getItem('afterloginparams')
        );
        if (!afterloginparams) {
          afterloginparams = {};
        }
        localStorage.removeItem('afterlogin');
        localStorage.removeItem('afterloginparams');
        if (afterlogin) {
          this.router.navigate([afterlogin], {queryParams: afterloginparams});
        } else {
          this.router.navigate(['/']);
        }
        this.finishedOnError('User not found');
      }
    );
  }

Solution

  • If you want to call change detection on the whole tree of Angular views then you should be using ApplicationRef instance like this:

    constructor(private appRef: ApplicationRef) {} 
    
    someMethod() {
      this.appRef.tick();
    }
    

    But I would advise you using cdRef.detectChanges() instead.

    constructor(private cdRef: ChangeDetectorRef) {}    
    
    someMethod() {
      this.cdRef.detectChanges();
    }
    

    This will call change detection on the current component and on all its children.