3

I updated from RC1 to RC2 and got this cryptic message - "Expression has changed after it was checked". The code is very simple.
The parent component has two children "sister" and "brother". Right after init, sister emits an event that is assigned to parent's variable and brother's Input() property is bound to the same variable. I think this is "classic" communication between siblings components using parent's variable.
It used to work in RC1, but not is RC2. I checked CHANGELOG.md, but have found no clue. What am I doing wrong? http://plnkr.co/edit/HMPAbImpWWeZrVjHyb6H?p=preview

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

@Component({
      selector: 'brother',
      template:'<h2>Brother has {{present}}</h2>'
})
export class Brother{
  @Input() present: string;
}

@Component({
  selector: 'sister',
  template:'<h2>Sister has {{_present}}</h2>'
})
export class Sister{
  @Output() present: EventEmitter<string> = new EventEmitter; 
  public _present: string = 'something';
  ngOnInit(){
    this.present.emit(this._present);
  }
}

@Component({
  selector: 'my-app',
  template: `
    <div class="container">
      <h2>Parent has {{present}}</h2>
      <brother [present]="present"></brother>
      <sister (present)="present=$event"></sister>
    </div>
  `,
  directives:[Brother,Sister]
})
export class AppComponent {
  public present: string;
}

2 Answers2

7

Yes, it has changed a bit. Specifically

fix(facade): change EventEmitter to be sync by default (#8761)

https://github.com/angular/angular/commit/e5904f4

So if you change your code from:

@Output() present: EventEmitter<string> = new EventEmitter; 

to:

@Output() present: EventEmitter<string> = new EventEmitter(true); 

Then it should work and you'll get the same behavior.

See also https://github.com/angular/angular/blob/master/modules/%40angular/facade/src/async.ts#L152

http://www.bennadel.com/blog/3071-synchronous-vs-asynchronous-eventemitters-in-angular-2-beta-14.htm

yurzui
  • 205,937
  • 32
  • 433
  • 399
1

Angular is processing template top-to-bottom, brother is checked first, sister is checked second. Sister fires synchronous event and changes brother field right after it(brother) has been checked. Angular detects this kind of errors in debug mode, in production mode this change will leave undetected(template will not be updated) until next detector pass. You can change order of components in app template and error will go away:

  <sister (present)="present=$event"></sister>
  <brother [present]="present"></brother>
kemsky
  • 14,727
  • 3
  • 32
  • 51
  • I've oversimplified a code. Sister and brother are symmetrical. Both of 'em must be on the first place at the same time. This appears to be impossible. Your workaround works! Thank you for your time. – Vladimir Turygin Jun 23 '16 at 07:55
  • The accepted answer fixed my issue (I cannot change the order of the components). I voted up because it made sense of what is happening. – Stephen Apr 07 '17 at 22:10