Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force child component to reload its data and its view when parent data changes Angular 4

I am using angular 4. I am a bit new to it although i had used Angular JS.

I have a parent component which has an array of objects

people: Person[]; //array of Person model

And in the parent component the user modifies people array through its view

Now there is a child component(personComponent) in the parent components view that iterates through the people array like so

<person *ngFor="let person of people; let i = index" [person]="person">

The child component shows percentges of each person in the personComponent

@Input() person:Person; //person model
percent:number;

ngOnInit(){
    this.percent = this.person.percent;
}

Now in the parent component, when a new person is added to the people array, each child component is supposed to have a new percent.

So i created a method in the parent component that calculates the percent of each person

setPercent(){
  this.people.forEach((p)=>{
     p.percent = Math.round((p.value/this.total_amount)*100) //total amount is a variable in the parent component
  })
}

Now every time a new person is added the setPerson method is called...the problem is that the child component does not update its data and the percent of each person in the people array is not updated.

I have tried using ngOnChanges on the child components person variable but that did not update the child components data and hence the child components view did not change as well. What can i do pls.

like image 380
Joshua Majebi Avatar asked Jan 28 '18 12:01

Joshua Majebi


People also ask

How do you communicate between parent and child components?

@Input() and @Output() give a child component a way to communicate with its parent component. @Input() lets a parent component update data in the child component. Conversely, @Output() lets the child send data to a parent component.


3 Answers

In your Person component, you take the percentage value on initialization and no longer update it. Instead of doing that, you could use the person property, that has the always up to date value. So you should be able to use it as

{{person.percentage}}

in your template.

like image 123
Justinas Simanavicius Avatar answered Nov 14 '22 23:11

Justinas Simanavicius


You can use the onChanges lifecycle hook.

// Child component

import { Component, OnChanges, SimpleChanges } from '@angular/core';

ngOnChanges(changes: SimpleChanges) {
    if (changes['person']) {
        console.log(changes['person'].currentValue);
    }
}
like image 32
Mark Avatar answered Nov 14 '22 22:11

Mark


On your child component use the following:

import { ChangeDetectionStrategy } from '@angular/core';
@Component({
  // your selector and template
  changeDetection: ChangeDetectionStrategy.OnPush
})

and in your parent component try the following:

import {ChangeDetectionRef} from '@angular/core';

and Inject it in the constructor:

constructor(private cd:ChangeDetectorRef){}

and in your method that update the percentages:

setPercent(){
 this.people.forEach((p)=>{
 p.percent = Math.round((p.value/this.total_amount)*100) //total amount is a 
   variable in the parent component
 });
 // TRY THIS
 this.cd.detectChanges();
 // OR THIS
 this.cd.markForCheck();
}

This code will tell the change detection to check of changes on your component and it's children.

like image 37
Nour Avatar answered Nov 15 '22 00:11

Nour