3

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>

2 Answers 2

8

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);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks bro this helps me lot's can you please explain me about use of markForCheck
Change detection in angular is done from the root to the bottom. This means that if a parent component has OnPush, the child component will also behave as OnPush, regardless of its setting. Imagine all the components are OnPush. If you call markForCheck from a child, it will bubble up to the root, marking -all- ancestors as 'dirty', which means in the next tick() (change detection), the components will get updated. (not the children of the child though). This is a bit of the opposite of detectChanges, because that will go from child to children and only update the dirty ones.
0

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]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.