Ajai
Ajai

Reputation: 391

How to work with change detection strategy on-push in angular for array

Here I'm trying to study how change detection work. having array(children) in parent component and in children using change detection OnPush. Trying to change the array by splice or push is still affecting the child component template. How come this works, even though the reference of the @Input does not change?

my parent component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewInit {
  children = [1,2,3,4,5,6,7,8,9]

  emit(j) {
    this.children.splice(j, 1);
  }
}

parent html

<div>
   <app-multi [input]="children" (output)="emit($event)"></app-multi>
</div>

my child component.ts

@Component({
  selector: 'app-multi',
  templateUrl: './multi.component.html',
  styleUrls: ['./multi.component.css'],
  changeDetection:ChangeDetectionStrategy.OnPush
})
export class MultiComponent implements OnInit,OnChanges,DoCheck,AfterViewInit{

  @Input('input') ele = [];

  data = [];

  @Output('output') outputEmi = new EventEmitter();

  ngOnInit() {
    this.data = this.ele;
  }

  clicks(value){
    this.outputEmi.emit(value);
  }

}

child html

{{name.name}}
<table>
    <tbody>
        <tr>
            <td *ngFor="let head of data; let i = index;">
                <span>{{head}}</span>
                <button class="delete" (click)="clicks(i)">x</button>
            </td>
        </tr>
    </tbody>
</table>

Upvotes: 3

Views: 4660

Answers (2)

Poul Kruijt
Poul Kruijt

Reputation: 71891

To my understanding, your question is that you are wondering why change detection works, even though the reference of the @Input doesn't change?

With the change detection strategy set to OnPush, the child component checks its template bindings only for a couple reasons:

  • A primitive or reference of an @Input() value has changed
  • A binded event has happened, which was declared inside the template (like (click))
  • The child component emits through @Output

In your case the second and last point happened, because of this the *ngFor inside your child template runs again, and realizes there is an extra addition to the array from the input.

Bottom line, so even though the reference of the array stays the same, and the @Input() does not change reference wise, there is still a change detection triggered, because the child component receives a binded (click) and emits an @Output.

If you were to update your code, and not use the @Output(), the change detection will still work, because an event was binded to the template:

clicks(value){
  this.input.splice(value, 1);
}

Upvotes: 8

onik
onik

Reputation: 1631

in order to trigger change detection, when it's OnPush you have to change the reference, so if you make splice it will not change reference it will just update the existing array, so I encourage you to do filter method instead of splice, but if you have to use splice than remember to renew the reference like this

this.children.splice(i,j);
this.children = [...this.children]

Upvotes: 0

Related Questions