4

Say we have component A as the parent component and component B as the child component. The child has an input what_is_x that is supplied by the parent. Something like this:

For the parent:

@Component({
  selector: 'cmp-A',
  directives: [ComponentB],
  template: `<cmp-B [what-is-x]="x"></cmp-B>`
})
export ComponentA {
  public x: any = [1, 2, 3];
  constructor() {
    setTimeout(() => this.x.push(10), 2000);
  }
}

For the child:

// component B with input what_is_x
@Component({
  selector: 'cmp-B',
  template: `{{what_is_x}}`
})
export ComponentB {
  @Input('what-is-x') public what_is_x: any;
}

My question is, if the parent changed x by some means, does the child get updated with the new value? According to the "Component communication" chapter in the developer guide (not released yet); it should! but it's not updated for me, tried all betas up till now (0,1,2)

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
abdulhaq-e
  • 626
  • 9
  • 19
  • I can't reproduce it, check this [plnkr](http://plnkr.co/edit/zZK61cFkZtzAyxwUnpLe?p=preview) – Eric Martinez Jan 30 '16 at 01:17
  • Thanks, the plnkr you provided works. But what about this [plnkr](http://plnkr.co/edit/MroX308iL4beGMcl70nU?p=preview). Appending values to the array is not reflected as you can see. – abdulhaq-e Jan 30 '16 at 03:13
  • 5
    The problem is that `push` doesn't return a new array. The Input will be updated when the change detector that the value bound to it has a new reference. See this [plnkr](http://plnkr.co/edit/bK3wsUybtFnH9Kae4sKy?p=info) using [concat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) that returns a new array, therefore a new reference. – Eric Martinez Jan 30 '16 at 03:37
  • 5
    What @EricMartinez said. Often, we have templates more like this in ComponentB: `
    {{item}}
    `. This works (using the same array reference) because bindings are created for each element of the array, so change detection will notice if an item is added or removed from the array, with, e.g., `push()`.
    – Mark Rajcok Jan 30 '16 at 03:41
  • @EricMartinez Thanks a lot, please submit it as an answer and perhaps include Mark's comment as well. – abdulhaq-e Jan 30 '16 at 06:07

1 Answers1

4

Update: As of beta.16, {{what_is_x}} will now update in the view, even if the array reference hasn't changed. See also {{myArray}} now updates in the view as of beta.16.


Original answer:

The default change detection algorithm looks for differences by comparing bound-property values by reference across change detection runs. -- doCheck() API doc

So as @Eric mentioned in a comment, the reason you are not seeing any updates in your view is because you are only binding to the array in your template – {{what_is_x}} – and since the array reference does not change when we modify the array (e.g., using push()), change detection does not detect any changes.

If this is really your use case, do as @Eric suggests and return a different array, then change detection will notice that the array reference has changed.

Normally, our templates bind to individual items of the array. E.g.,

<div *ngFor="#item of what_is_x">{{item}}</div>

Since there is a binding created for each item of the array, if we add or remove or modify an item, change detection will notice (and we do not need to return a different array).

For debugging, if you instead use {{what_is_x | json}}, you'll also see the view update when the array changes. (This is because the JsonPipe is stateful, which causes Angular change detection to evaluate it every change detection cycle.)

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492