Difference between @observable and @bindable

I saw the question asked several times, so maybe it’s time to put down something in discourse, as Gitter may not be suitable for retaining answers.

# @observable @bindable
1 Works any where Works in Aurelia templating context
2 Change handler {propertyName}Changed is called synchronously Change handler {propertyName}Changed is call asynchronously
3 Doesn't call propertyChanged(name, newValue, oldValue) Can call propertyChanged(name, newValue, oldValue)
4 Cannot be used to bind between custom elements Can be used to bind between custom elements
24 Likes

I’d expect to something like this on the cheat sheet.

3 Likes

And here is some more (-:

1 Like

@observable changed event will fire immediately if you give it a default value. Caused me some headaches. I was using it to watch a radio button selection to change how a data grid is filtered. It was causing data to be fetched twice. The best workaround was to track the page life cycle which I did by setting a bool in the activate method. In the changed handler I’d only continue my logic if the page was past the activate state

2 Likes

The issue you have only exists in TypeScript, where it converts field initialization into property assignment in constructor. Babel has no issue with that. Because it’s a property assignment in constructor, it will call the change handler straightaway when you create the object, thus many parts of the object may not be ready for and break. To deal with it, you can add a flag to ensure that it has passed a certain cycle like bind or attached. (e.g isAttached = true)

That said, we can introduce another config to help bring field initialization to TypeScript user, it could be like the following:

export class MyApp {
  @observable({
    // default to an empty string
    defaultValue: ''
  })
  name: string;

  nameChanged(name: string) {
    // won't be called straightaway
  }
}

instead of

export class MyApp {
  @observable()
  // default to property assignment in constructor
  name: string = '';

  nameChanged(name: string) {
    /* will be called straightaway
       when instance of this class is created
    */
  }
}

Would be nice if we can know what TypeScript users’ thoughts are on this one.

2 Likes

Thanks for that write up. Sadly this is the kind of stuff that really irks anyone trying to use this framework. Poor documentation. Look at the API documentation. I know it’s open source, but the developers that work a feature need to do a better job of at least listing the capabilities. You find a happy little sample showing off a feature but rarely are gotchas pointed out. Don’t need detailed tutorials. I know there is a push for documentation right now, sadly I feel like that is going to come too late for some newcomers. I have too much time invested in the framework to start over.

http://aurelia.io/docs/api/binding/function/observable

Agree that this can be improved more, would be nice if you could give the doc improvement a shot or put together a PR to add the feature :wink:

1 Like

I’m not sure if i can really document features I don’t fully understand. But what I think would be useful is on the API pages to allow examples and remarks just like the Microsoft documentation site. I’d be happy to do examples that can be peer reviewed.

I investigated a bit
There is a possibility to add examples to annotation comments
Yet to figure out is weather tooling used for docs supports extracting those

1 Like

I’m using that isAttached trick you mention a lot. On one hand it would be nice to avoid. But on the other hand - with your suggestion - it really doesn’t solve the problem that someone might try to do a normal assignment to the member and end up adding the isAttached flag anyway… Putting stuff in the @bindable call seems a bit hidden…

This might not be very constructive, I just wanted to share my thoughts.

1 Like