I have an Aurelia component that is just supposed to display a list of items. The component's model has an "items" property which is bindable:
@bindable items = [];
The component template displays the list using a simple repeat attribute:
<div repeat.for="item of items">
${item.id} </div>
When I push a new item in my bound array from the page's viewmodel where the component is used, I can see the item being added as the list is refreshed and the new item appears. My problem is that I need to perform other actions when the 'items' array is modified so I tried to add a collectionObserver to the component like this:
import {BindingEngine, inject} from 'aurelia-framework';
@inject(BindingEngine)
export class GridControl {
@bindable items = [];
constructor(bindingEngine) {
this.items = [];
let subscription = bindingEngine.collectionObserver(this.items)
.subscribe(this.listChanged);
}
listChanged(splices) {
// do some stuff
}
}
But my 'listChanged' handler never gets called. Any idea why?
In the constructor, bindingEngine.collectionObserver(this.items)
is called.
Later, when the component is data-bound, this.items
is assigned a different array instance via the data-binding. This different array instance is not the one you passed to the binding engine for observation.
Try doing something like this:
import {BindingEngine, inject} from 'aurelia-framework';
@inject(BindingEngine)
export class GridControl {
@bindable items;
constructor(bindingEngine) {
this.bindingEngine = bindingEngine;
}
listChanged(splices) {
// do some stuff
}
subscribeItems() {
if (this.items) {
this.subscription = this.bindingEngine.collectionObserver(this.items)
.subscribe(splices => this.listChanged(splices));
}
}
unsubscribeItems() {
if (this.subscription) {
this.subscription.dispose();
this.subscription = null;
}
}
itemsChanged() {
this.unsubscribeItems();
this.subscribeItems();
}
unbind() {
this.unsubscribeItems();
}
}