I’m posting this in case anyone else runs into this little snag.
While experimenting with aurelia-store, I decided I’d like to avoid making “temporary” properties on my view-model for the purpose of binding to form data. Instead, I wanted to bind my user input directly to the properties pluck
ed from the state, and furthermore make them @observable
, so I could easily dispatch
a state update whenever any of them changed. (Is this a good idea? I don’t know; someone please weigh in if you have an opinion.)
import stuff
@autoinject
@connectTo({
selector: (store) => store.state.pipe(pluck("myProperty")),
target: "myProperty"
})
export class MyVM {
@observable myProperty; // OK - this will hold the latest plucked value, *and* be observable
myPropertyChanged(newVal, oldVal){
this.store.dispatch("updateMyProperty", newVal);
}
constructor(store){
store.registerAction("updateMyProperty", (state, newVal) => return Object.assign({},state, {myProperty: newVal});
}
}
<template>
<form><input type="text" value.bind="myProperty"></input></form>
</template>
Now assuming my syntax is correct (I haven’t tested the exact code above), this should pipe the value of store.state.myProperty
into MyVM.myProperty
; and any changes to MyVM.myProperty
should dispatch an update to the store. And conveniently, @observable
properties only call their change handler if newVal
is different from oldVal
, so we shouldn’t get stuck in an endless update loop that crashes our browser.
…right?
But that code will crash your browser!
Luckily, the reason and the solution are very simple: the @observable
decorator and the @connectTo
decorator both look for a change handler, and they both expect it to be named according to the same convention: [property-name]Changed(newVal, oldVal)
. Writing a single change handler that accidentally fits both those slots is very easy to do, and it causes some wild behaviour.
Solution: just use the syntax @observable({changeHandler: 'someOtherFunctionName'})
to define your observable change handler, and you’re all set. You can connectTo, pluck, observe/dispatch, and bind using a single property name, and it all works seamlessly.