@children
ts
children<T extends Base>(name: string, callbacks?: WatchChildrenCallbacks<T>): ValueDecorator<ChildrenCollection<T>>
children<T extends BaseConstructor>(ComponentClass: T, callbacks?: WatchChildrenCallbacks<InstanceType<T>>): ValueDecorator<ChildrenCollection<InstanceType<T>>>Field sugar over $watchChildren().
Usage
ts
@component({ name: 'Slider', components: { SliderItem } })
class Slider extends Base {
// Exact `config.name`.
@children('SliderItem')
items!: ChildrenCollection<Base>;
// Also every named subclass, through `instanceof`.
@children(SliderItem)
allItems!: ChildrenCollection<SliderItem>;
reset() {
for (const item of this.items) {
item.$el.removeAttribute('data-option-active');
}
}
}The collection is live, in document order whatever the mount order is.
Callbacks
ts
@component({ name: 'Slider', components: { SliderItem } })
class Slider extends Base {
@children(SliderItem, {
added(item) {
// `this` is the Slider instance.
this.reindex();
},
removed(item) {
this.reindex();
},
})
items!: ChildrenCollection<SliderItem>;
reindex() {}
}The callbacks are bound to the instance, which is the one thing this form gives over the function form.
It is instance-scoped
The subscription stays active through unmount and mount cycles, for the whole life of the watching instance. It is never released and dies with the element.
The initial sweep is deferred to a microtask, because a field initializer runs before the element is in place; the announcement listeners attach at once, so nothing is missed.
The function form
js
import { Base } from '@studiometa/js-toolkit';
class SliderItem extends Base {
static config = { name: 'SliderItem' };
}
class Slider extends Base {
static config = { name: 'Slider', components: { SliderItem } };
items = this.$watchChildren(SliderItem, {
added: (item) => this.reindex(),
removed: (item) => this.reindex(),
});
reindex() {}
}Identical behaviour, no build step. Note the arrow functions: the function form does not bind the callbacks for you.