0

I have a situation where I have an inner component :

@Component({
  selector: 'hello',
  template: `<h1>Name   =  {{name}}!</h1> `
})
export class HelloComponent {
  @Input() name: string;
  @Output() ev: EventEmitter<string> = new EventEmitter<string>();

  constructor(private cdRef: ChangeDetectorRef) {  }

  ngOnInit() {
    this.ev.emit("new name");
    this.cdRef.detectChanges();
  }
}

Where in the parent component :

 <hello name="{{ name }}" (ev)="changeName($event)"></hello>


@Component({
  selector: 'my-app',
  templateUrl: './app.component.html'
})
export class AppComponent {
  name = 'Angular 5';

  changeName(e) {
    this.name = e;
    console.log(e)
  }

}

So basically , when the inner component loads , it emits an event which in turn received by parent and re-set the value of its inner component.

But this code ( and I do know why) - yields an exception :

Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'Angular 5'. Current value: 'new name'.

But according to other answers in SO:

This line : this.cdRef.detectChanges(); should have caused a new detection and prevent the exception.

I already know that setTimeout()... does solve it in a hacky way.

Question:

Why doesn't detectChanges prevent the exception ?

Stackblitz

Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • Does an `Output` triggers change dtetection ? –  Jan 25 '18 at 09:04
  • @trichetriche Who said that ? `this.cdRef.detectChanges()` should trigger – Royi Namir Jan 25 '18 at 09:05
  • this was a question ... But from what I understand, if it doesn't trigger a change detection, then it means it changes the value of a variable after it has been checked, thus making the error, doesn't it ? –  Jan 25 '18 at 09:10
  • @trichetriche Yeah I don't know what i'm missing here. Basically it's a sub component that yields an event to tell her parent to set a new value in it. – Royi Namir Jan 25 '18 at 09:11
  • Well, as I said just before, `if it doesn't trigger a change detection, then it means it changes the value of a variable after it has been checked, thus making the error`. Maybe that is why a timeout is working while an emit isn't –  Jan 25 '18 at 09:12
  • @trichetriche so in which ng-event you'd emit ? ngoninit is one of the first – Royi Namir Jan 25 '18 at 09:40
  • I would use a timeout I guess –  Jan 25 '18 at 09:42
  • Do you know where the error comes from? ` It comes from parent component ` – yurzui Jan 25 '18 at 10:06
  • @yurzui yes : when I set a new name : https://i.imgur.com/pyF3Nxr.jpg – Royi Namir Jan 25 '18 at 10:06
  • You call changeDetection in child but there nothing has changed after was checked – yurzui Jan 25 '18 at 10:07
  • @yurzui so what should I in case where a child emits event which causes the parent to change input value of his son ? – Royi Namir Jan 25 '18 at 10:07
  • If you call detectChanges in parent component then you will run into `maximum call stack size exceeded` – yurzui Jan 25 '18 at 10:08
  • @yurzui Right. I tried application.tick() in parent and got recursion error. – Royi Namir Jan 25 '18 at 10:08
  • https://stackblitz.com/edit/angular-ik4jkd?file=app/hello.component.ts – yurzui Jan 25 '18 at 10:11
  • @yurzui thank you very much. So from my understanding , `detectchanges` only trigger change detection from this point , downwards. right ? that's why you called it from above ? – Royi Namir Jan 25 '18 at 10:17
  • Yep, it goes from current view down through all child views. It can omit detect changes for views that have OnPush strategy. setTimeout runs macrotask after that app.tick will be called. If you call app.tick directly during current execution of tick then you will get exception about recursive calling. – yurzui Jan 25 '18 at 10:20

0 Answers0