Matthew Brown February 2016

Angular2 Async Data Issue

I have a component that is reliant upon an asynchronously fetched object. There are also child components in the template that rely on some data from this same object.

The problem I am having seems to be a classic race condition, but I'm not familiar enough with Angular 2 to understand the solution.

Take this for instance:

export class SampleComponent {
    constructor(service: SomeService) {
        this.service = service;
        this._loadData();
    }

    private _loadData() {
        this.service.getData().subscribe(data => this.data = data);
    }
}

But in the template, I have child components to display certain parts of this.data:

<taglist tags="data?.tags"></taglist>

Now the Component for taglist looks something like:

@Component({
    selector: 'taglist',
    directives: [NgFor],
    inputs: ['tags'],
    template: `<span *ngFor="#tag of tags">{{ tag }}</span>`
})

export class TagList {
    public tags: Array<string> = [];

    constructor() {
        //
    }
}

Because tags input is received from an async loaded dataset, its not present when the Tag Component is initialized. What can I do so that when this.data load is finished, the sub components that use it will automatically access the newly loaded data?

Thank you for any insight you may be able to provide me!

Answers


Günter Zöchbauer February 2016

Implement ngOnChanges() (https://angular.io/docs/ts/latest/api/core/OnChanges-interface.html)

@Component({
    selector: 'taglist',
    directives: [NgFor],
    inputs: ['tags'],
    template: `<span *ngFor="#tag of tags">{{ tag }}</span>`
})

export class TagList {
    public tags: Array<string> = [];

    constructor() {
        //
    }

    ngOnChanges(changes: {[propName: string]: SimpleChange}) {
      console.log('ngOnChanges - tags = ' + changes['tags'].currentValue);
    }
}

For angular to handle the binding also use

<taglist [tags]="data?.tags"></taglist> or <taglist tags="{{data?.tags}}"></taglist>

otherwise it's a simple string to attribute assignment Angular doesn't handle.


jhadesdev February 2016

This is the usual use case for the built-in async pipe, that is meant to be used to easily consume observables.

Try the following, first create a getter than returns directly the service layer observable:

get data(): Observable {
    return this.service.getData();
}

Then you can consume this observable directly in the template using the async pipe:

<span *ngFor="#tag of data | async">{{ tag }}</span>

Post Status

Asked in February 2016
Viewed 2,379 times
Voted 5
Answered 2 times

Search




Leave an answer