7

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!

2 Answers 2

5

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

@Component({
    selector: 'taglist',
    inputs: ['tags'],
    template: `<span *ngFor="let 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.

Sign up to request clarification or add additional context in comments.

3 Comments

So I did try this prior, And when I console.log chages['tags'].currentValue it prints the string 'data?.tags' instead of the evaluated value :/
I see. Use <taglist [tags]="data?.tags"></taglist> or <taglist tags="{{data?.tags}}"></taglist>
Awesome, I'll try this in a min here. Thanks for the pointers
0

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="let tag of data | async">{{ tag }}</span>

1 Comment

Do I need to specify async in @Component pipes: [] ?

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.