Observing Objects and Arrays in Aurelia

So you’ve run into a wall or perhaps just curious on how to expand your observer-fu? Today we are going to be learning how to observe Arrays and Objects in Aurelia.

Many of the concepts you will learn here can be used to use Aurelia components outside of Aurelia, once you understand the rules you can use them to your advantage.

Why you won’t see @observable here

In another post here I talk about the @observable decorator and how you can use it, but you won’t see it being used here.

The @observable decorator and underlying functionality is only for observing class properties, it does not work for arrays or objects (unless you reassign them). When working with arrays, you’ll be; splicing, pushing and popping so it won’t work for those cases.

Observing Arrays

Using the Aurelia Collection Observer we can observe array changes and our subscribe method will return splices.

The syntax kind of looks similar to that of the Event Aggregator, except we’re observing a collection and not working with events.

import {BindingEngine, inject} from 'aurelia-framework';

@inject(BindingEngine)
export class MyClass {
    constructor(bindingEngine) {
        this.bindingEngine = bindingEngine;
        this.theList = [];

        let subscription = this.bindingEngine.collectionObserver(this.theList).subscribe(this.listChanged);
        
        // Dispose of observer when you are done via: subscription.dispose();
    }

    listChanged(splices) {

    }
}

What are splices?

You probably assume that “splices” is simply a new array of added items on our callback. This is not the case. The splices argument returns an object with three properties; addedCount, index and an array called removed.

Using these values, we can determine if an item was inserted or removed in an array. In the case of removed, when we remove an item from an array it will be in this removed array so we have a record of the deletion.

Observing Object Properties

In Aurelia you can use the BindingEngine class which has a propertyObserver method which handles observing object properties.

Once again, the syntax looks identical to our array example above, except the propertyObserver method requires the object we are observing as the first argument and the second argument is a string name of the property.

import {BindingEngine, inject} from 'aurelia-framework';

@inject(BindingEngine)
class MyClass {
  constructor(bindingEngine) {
    this.bindingEngine = bindingEngine;
    this.observeMe = 'myvalue';

    let subscription = this.bindingEngine
      .propertyObserver(this, 'observeMe')
      .subscribe((newValue, oldValue) => { this.objectValueChanged(newValue, oldValue) });

    // Dispose of observer when you are done via: subscription.dispose();
  }

  objectValueChanged(newValue, oldValue) {
    console.log(`observeMe value changed from: ${oldValue} to:${newValue}`);
  }
}

Unlike our collection observer, we don’t get splices back and get the values themselves. The propertyObserver works very similar to how @bindable attributes in custom attributes and elements does with a changed callback.

Conclusion

The collectionObserver is for collections and not only does it work for arrays, but you can use it on other collection types like a Map as well. The propertyObserver is for object properties themselves. That’s all you need to remember.