Observing Array Properties in Aurelia

aurelia observable and bindable
aurelia computedfrom
aurelia bindable
aurelia events

I have a property on my class:

class Control {
    @bindable households;

    get people() {
        return households
            .map(household => househould.people)
            .reduce((g1, g2) => g1.concat(g2), []);
    }
}

Which I use to compute a collection of all people[] within all households which is then rendered here:

<ul>
    <li repeat.for="person of people">
        ${person.firstName} ${person.lastName} - ${person.phone}
    </li>
</ul>

I need the list to update whenever people are added to a household, OR if any of the rendered properties, firstName, lastName, phone, for any element in the computed collection is updated. How can I do this in Aurelia? If I use @computedFrom() it will not detect changes to elements of the array, and since the list of people in all households is dynamic, I cannot just create an observer for each element without creating a system for managing when observers should be subscribed / unsubscribed.

Use Dirty Checking

Leave off @computedFrom() and you'll achieve the desired behavior.

export class App {
  @bindable households;
  get people() {
    const households = this.households || []; // Make sure househoulds is defined.
    return households.reduce((people, household) => people.concat(household.people), []);
  }
}

https://gist.run/?id=040775f06aba5e955afd362ee60863aa

You can create multiple propertyObserver calls to observe multiple properties, but you cannot observe objects as a But not for observing changes to arrays. Observing Array Properties in Aurelia. Ask Question Asked 1 year, 6 months ago. aurelia property observation for an object that is bound from the parent. 9.

Right as I was about to give up on being able to Google for a solution, Aurelia Signaling came to the rescue. This code ended up working for me:

<ul>
    <li repeat.for="person of people">
        <!-- May work without this rendering method,
            this is just closer to what my actual code is doing. -->
        ${renderPersonInfo(person) & signal: 'example-signal'}
    </li>
</ul>

And the class:

import {BindingSignaler} from 'aurelia-templating-resources';

@inject(BindingSignaler)
class Control {
    @bindable households;

    constructor(bindingSignaler) {
        this.bindingSignaler = bindingSignaler;
        //Obviously, you can have this trigger off any event
        setInterval(() => this.bindingSignaler.signal('example-signal'), 1000);
    }

    get people() {
        return households
            .map(household => househould.people)
            .reduce((g1, g2) => g1.concat(g2), []);
    }
}

Use Dirty Checking. Leave off @computedFrom() and you'll achieve the desired behavior. export class App { @bindable households; get  Binding: Observables Using observables with Aurelia. Observable Properties. Have you ever needed to perform an action when a property is changed? If you have, that's a great use of property observation. To observe a property, you need to decorate it with the @observable decorator and define a method as the change handler. This method can receive 2 parameters: the new value and the old value.

You must avoid dirty-checking as far as possible, signals are the perfect option for your scenario. Just bear in mind that if you want to use computedFrom on an array you can do so by watching its length property for instance rather than dirtyChecking, sth like the following @computedFrom("myArray.length")

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. When it comes to objects, Aurelia couldn’t make it any easier to observe them for changes and react accordingly and in this topic, we’ll be showing you how easy it is to watch object properties for changes in your Aurelia applications. Say hello to BindingEngine Aurelia’s binding system provides an interface called BindingEngine which exposes a few methods for watching not only objects

Note: the following doesn't cover Aurelia's strategies for observing Arrays. That's a subject for another post :) 1. Is the object being observed a  Aurelia employs several strategies when observing object properties. The best strategy is chosen depending on the features of the browser and the type of object/property being observed. The best strategy is chosen depending on the features of the browser and the type of object/property being observed.

We can't do deep observation of collections by default. That would be very, very bad. I'm willing to say it could potentially ruin Aurelia's  @atsu85 - the binding system observes property changes- if you put <input value.bind="foo.bar.baz"> in an html template or in @computedFrom('foo.bar.baz'), the binding system will observe the foo property for changes, foo's bar property for changes and bar's baz property for changes. It doesn't check "is the value an array? yes? also observe

Observing array length with @computedFrom("array.length") works, is it officially supported? heart 2. Binding: The Binding Engine How data-binding works in Aurelia. Introduction. The binding engine is an utility export of aurelia-binding module, which gives some higher level APIs for dealing with observation, which leverages aurelia binding system primitives under the hood.

Comments
  • if you just use a getter, without computedFrom, and without signals - you should get the same effect - because aurelia will default to the dirty strategy of recomputing the getter 5 times a second. ALSO: dont forget to dispose your interval on detached.
  • dirty-check is not a sin :-) It's the only trick that angular v1 needed.
  • Hmm, I've tested with this and it didn't work for me. Switched to a simple method and behavior is quite different.