Search code examples
angularangular2-changedetection

Angular2 component not rendering when data changes


I have a very simple Angular2 component:

@Component({
    moduleId: module.id,
    selector: 'app-people',
    templateUrl: 'people.component.html'
})
export class PeopleComponent implements OnInit {

    people: any[] = [];

    constructor(private peopleService: PeopleService) {
    }

    ngOnInit() {
        this.peopleService.getPeople()
            .subscribe(this.extractPeople);
    }

    extractPeople(result: any) {
        this.people = result.people;
    }
}

On initialization, I see that ngOnInit() is called which calls peopleService.getPeople(). I also see the asynchronous return which calls extractPeople(). However, even after this.people gets updated the component is not re-rendered. Why is this happening? Why is the change not detected?

Edit Here's some related code for additional context:

people.component.html

<tr class="person-row" *ngFor="let person of people">
    <td class="name">{{person.name}}</td>
</tr>

people.service.ts

getPeople(): Observable<any> {
    return this.http
        .get(peopleUrl)
        .map(response => response.json());
}

If I console.log(this.people) inside PeopleComponent.extractPeople(), I correctly get an array of people:

[
    {
        id: 11,
        name: "John Smith"
    },
    ...
]

However, the component is not re-rendered at this point. The view is still showing the initial value of of the people array which is empty. In fact, if I initialize the array with a couple of hard coded people, they show up correctly on the initial rendering of the component. However this list is not re-rendered when the real http data arrives! It is as if change detection is not triggering at all.


Solution

  • I suppose that you need to use arrow function to retain this at this line:

    this.peopleService.getPeople()
       .subscribe(this.extractPeople); <=== here
    

    This way your code should look like this:

    this.peopleService.getPeople()
       .subscribe((res) => this.extractPeople(res));
    

    More information about using arrow function you can find here https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Lexical_this