简体   繁体   中英

Angular2 change detection in lifecycle hook methods

I want to show a spinner in ngOnInit() and hide it in ngAfterViewInit(). But this is not working:

  • without setTimeout(), nothing happen
  • with setTimeOut(), the spinner show and hide (blink), but after ngAfterViewInit()

http://plnkr.co/edit/M1g7DT1Eks2gtuSXi1B1?p=preview

In this example the spinner component (spinner.ts) is a div tag that changes background color.

import {Component, Input} from '@angular/core'

@Component({
  selector: 'my-spinner',
  template: `
    <div [style.background-color]="status ? 'red' : 'yellow'" >
      spinner is {{status}}
    </div>
  `,
})
export class MySpinner {
  @Input() status: boolean;

  status:boolean;
  constructor() {
    this.status = false;
  }

  getColor() {
    if (status) {
      return "red";
    } else {
      return "yellow";
    }
  }

  ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
        for (let propName in changes) {
            let chng = changes[propName];
            let cur  = JSON.stringify(chng.currentValue);
            let prev = JSON.stringify(chng.previousValue);
            console.trace(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
        }
    }
}

On clic on 'link to my component' (mycomponent.ts), I want the background color spinner is red between ngOnInit() and ngAfterViewInit().

import {Component, Input, ApplicationRef} from '@angular/core';
import {AppService} from './appservice';

@Component({
  selector: 'my-component',
  template: `
    <div>
      This is my component!
    </div>
  `,
})
export class MyComponent {

  constructor(private appSvc: AppService) {

  }

  ngOnInit(): void {

    this.appSvc.setVisible(true);
    console.log('MyComponent - ngOnInit');
  }

  ngAfterViewInit() {
    var start = new Date().getTime();
        for (var i = 0; i < 1e7; i++) {
            if ((new Date().getTime() - start) > 10000){
                break;
            }
        }

    //setTimeout(() => { this.appSvc.setVisible(false)});
    this.appSvc.setVisible(false);

    console.log('MyComponent - ngAfterViewInit');
  }

}

What is the solution?


UPDATE

I update the sample http://plnkr.co/edit/M1g7DT1Eks2gtuSXi1B1?p=preview to use observable.

I set the spinner to show in ngOnInit() but ngOnChanges() of the spinner component is called after ngAfterViewInit()

The log console is :

VM437 AppService - setVisible - true  
VM439 mycomponent.ts!transpiled:33 MyComponent - ngOnInit  
VM439 mycomponent.ts!transpiled:37 MyComponent - ngAfterViewInit -begin  
VM439 mycomponent.ts!transpiled:47 MyComponent - ngAfterViewInit -end  
**VM440 spinner.ts!transpiled:38 status: currentValue = true, previousValue = fals**  
VM437 appservice.ts!transpiled:27 AppService - setVisible - false  
VM439 mycomponent.ts!transpiled:45 Observable Complete  
**VM440 spinner.ts!transpiled:38 status: currentValue = false, previousValue = true**

So it seems that there is no immediately change detection in lifecycle hook methods? Right or wrong?

To achieve this, I think it's better put directly the spinner as non-angular component inside the <my-app> tags. In this way, you can obtain a spinner that display until the application is fully loaded.

If you try to achieve this using angular components, the spinner does not show until the angular app is loaded, and when it is loaded the spinner at that moment is useless.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM