3

I would like to pass an array of data to a child component. Depending on events in the child component the data may change:

HTML (parent):

<child-component [data]="array" (event)="updateArray()"/>

TypeScript (parent).

updateArray() {
  ...
  this.array.push(more data)
  ...
}

The new data in the array should be re-rendered in the child component. But Angular does not regonize the changes.

I found a solution: https://chrislo.ca/angular-2345-change-detection-on-data-bound-array-pushunshift-popshift-or-splice/

pushAndUpdate(x) {
  this.myArray = [...this.myArray, x];
}

It creates a new array.

My question is: is this the best way or is there something better?

5
  • 1
    the better option is update Angular to 8 :) see, e.g. stackblitz.com/edit/… Commented Feb 3, 2020 at 10:11
  • Was there a change in the change detection of Angular? Commented Feb 3, 2020 at 10:16
  • No. Do you have the OnPush change detection strategy set on the child? That'd probably comes from there. BUT. To answer your question, working with immutable data is the way to go. (and keeping onpush..) Commented Feb 3, 2020 at 10:18
  • I complementary my comment in an answer with two fools examples Commented Feb 3, 2020 at 10:30
  • I complementary my comment in an answer with two fools examples. If we choose change DetectionStrategy onPush, we need change the array or call to detectChanges Commented Feb 3, 2020 at 10:36

2 Answers 2

3

if you put ChangeDetectionStrategy.OnPush in children, you need use this.myArray = [...this.myArray, x]; -change the array- else you has no make any change.

the stackblitz

//hello, no change ChangeDetectionStrategy
@Component({
  selector: 'hello',
  template: `Hello <div *ngFor="let item of array">{{item}}</div>`,
  styles: [`h1 { font-family: Lato; }`],
})
export class HelloComponent  {
  @Input() array: any[];
}

//hello2, ChangeDetectionStrategy
@Component({
  selector: 'hello2',
  template: `Hello2 <div *ngFor="let item of array">{{item}}</div>`,
  styles: [`h1 { font-family: Lato; }`],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class HelloComponent2  {
  @Input() array: any[];
}

main.component:

<hello  [array]="array"></hello>
<hr/>
<hello2 [array]="array"></hello2>

<button (click)="click()">push</button>
<button (click)="click2()">CopyArray</button>


array=[1,2,3,4]
  click2(){
    this.array=[...this.array,1]
  }
  click(){
    this.array.push(1)
  }

Update there another way

In main component:

  constructor(private cdr:ChangeDetectorRef){}
  click3(){
    this.array.push(1)
    this.cdr.detectChanges()
  }
Sign up to request clarification or add additional context in comments.

Comments

-2

you can use subject/observables with markForCheck() in your child-component


@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
  @Input() data: Observable<any>;
  foods: string[] = [];

  constructor(private cd: ChangeDetectorRef) {}

  ngOnInit() {
    this.data.subscribe(food => {
      this.foods = [...this.foods, ...food];
      this.cd.markForCheck();
    });
  }
}

and in your function, you can use a subject like this

subject = new Subject();
pushAndUpdate(x) {
  this.myArray.push(x);
  this.myArray = this.subject.next(this.myArray);
}

for more details on the subject check out this

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.