Building  Large-Scale Web Applications with Angular
上QQ阅读APP看书,第一时间看更新

The @ViewChildren decorator

@ViewChildren works similarly to @ViewChild, except it can be used to inject multiple child types into the parent. Again taking the previous audio component above as an example, using @ViewChildren, we can get all the MyAudioDirective directive instances in WorkoutAudioComponent, as shown here:

@ViewChildren(MyAudioDirective) allAudios: QueryList<MyAudioDirective>; 

Look carefully; allAudios is not a standard JavaScript array, but a custom class, QueryList<Type>. The QueryList class is an immutable collection that contains the reference to the components/directives that Angular was able to locate based on the filter criteria passed to the @ViewChildren decorator. The best thing about this list is that Angular will keep this list in sync with the state of the view. When directives/components get added/removed from the view dynamically, this list is updated too. Components/directives generated using ng-for are a prime example of this dynamic behavior. Consider the preceding @ViewChildren usage and this view template:

<audio *ngFor="let clip of clips" src="/static/audio/ "+{{clip}}></audio> 

The number of MyAudioDirective directives created by Angular depends upon the number of clips. When @ViewChildren is used, Angular injects the correct number of MyAudioDirective instances into the allAudio property and keeps it in sync when items are added or removed from the clips array.

While the usage of @ViewChildren allows us to get hold of all MyAudioDirective directives, it cannot be used to control the playback. You see, we need to get hold of individual MyAudioDirective instances as the audio playback timing varies. Hence the distinct @ViewChild implementation.

Once we get hold of the MyAudioDirective directive attached to each audio element, it is just a matter of playing the audio tracks at the right time.