Vibol
Vibol

Reputation: 785

Aurelia binding, bind a function to a property of an object without using propertyObserver

So usually, when I want to subscribe to a variable, I would just declare the variable and declare a function with the variable name followed by the word 'Changed' at the end of the function such as below:

test = '';

testChanged() {
// do stuff here
}

Aurelia provides a very nice way of handling this. However, what do I do if I want to subscribe to a property that is inside an object without using the bindingEngine.propertyObserver

For example:

model = {
  a: '',
  b: ''
}

How do I subscribe to model.a using the same convention as above?

Upvotes: 1

Views: 1131

Answers (1)

Dwayne Charrington
Dwayne Charrington

Reputation: 6632

You will want to use the Object.defineProperty method to watch an objects specific properties for changes. I believe this is how the Aurelia @bindable and @observable methods work behind the scenes in most cases.

Object.defineProperty(this.model, 'a', {
    configurable: true,
    enumerable: true,
    get: () => {
        return this.model.__a;
    },
    set: (v) => {
        this.model.__a = v;
        this.modelChanged(v);
    }
});

First thing worth mentioning is inside of the setter method set you can't set the original value, otherwise it will trigger a recursive loop and throw a stack error, so you assign the value to a double underscore prefixed name, akin to a temporary hidden variable.

Then define our callback function inside of our class:

modelChanged(value) {
    console.log(value);
}

Lastly, tie it all together and use a setTimeout to test:

export class MyViewModel {
    model = {
        a: '',
        b: ''
    };    

    constructor() {
        Object.defineProperty(this.model, 'a', {
            configurable: true,
            enumerable: true,
            get: () => {
                return this.model.__a;
            },
            set: (v) => {
                this.model.__a = v;
                this.modelChanged(v);
            }
        });

        setTimeout(() => {
            this.model.a = 'HELLO!';
        }, 3000);
    }

    modelChanged(value) {
        console.log(value); // After 3 seconds, this should be "HELLO!" in the browser console.
    }
}

Having said all of this, worthy of note is the bindingEngine.propertyObserver functionality essentially does the same thing under hood. I would honestly consider just using propertyObserver instead of introducing a heap of lines of code into your app to watch a property.

Upvotes: 3

Related Questions