Reputation: 34288
In Ember.js, creating a observer which reacts to changes in sub-properties which is an array leads to non intuitive behavior. If the observer directly observes the array property, it fails to fire while if it observes a binding to the same property, it works as expected.
A simple example:
Handlebars:
<script type="text/x-handlebars">
<b>App.View1.name:</b> {{App.View1.name}} <br />
<b>App.View2.name:</b> {{App.View2.name}}
</script>
Javascript:
App = Em.Application.create();
// A common dependency for two views
var dependency = Em.Object.create({
prop: []
});
// Directly observes dependency.prop
App.View1 = Em.View.create({
dependency: dependency,
name: "Foo",
changeName: function () {
this.set("name", "Bar");
}.observes("dependency.prop")
});
// Indirectly observes dependency.prop via a binding
App.View2 = Em.View.create({
dependency: dependency,
name: "Foo",
changeName: function () {
this.set("name", "Bar");
}.observes("prop"),
propBinding: "dependency.prop"
});
// Updating the 'prop' property of dependency with an element.
dependency.get("prop").pushObject("An object.");
I have put it up on JSFiddle here: http://jsfiddle.net/kbaXG/50/
Here, App.View1.name
is NOT updated (stays "Foo") while App.View2.name
is updated (to "Bar").
Is this expected behavior and is creating a binding an acceptable workaround?
Upvotes: 1
Views: 2307
Reputation: 16163
Bindings is a fundamental concept in Ember.js, so don't hesitate to use it :)
Your example works if you create a binding for your dependency
, see http://jsfiddle.net/pangratz666/Gqc7Q/:
App = Em.Application.create({
VERSION: "0.1"
});
App.dependency = Em.Object.create({
prop: []
});
App.View1 = Em.View.create({
dependencyBinding: 'App.dependency',
name: "Foo",
changeName: function () {
this.set("name", "Bar");
}.observes("dependency.prop")
});
App.View2 = Em.View.create({
dependencyBinding: 'App.dependency',
name: "Foo",
changeName: function () {
this.set("name", "Bar");
}.observes("prop"),
propBinding: "dependency.prop"
});
// Updating the 'prop' property of dependency.
dependency.get("prop").pushObject("An object.");
UPDATE
The problem was that you are changing the contents of an array and not the array itself. So you have to change the observer path to dependency.prop.@each
, see http://jsfiddle.net/pangratz666/3QccA/. But I don't know why it's working with the binding approach and not with this one... You should file a ticket on GitHub.
As a last note, the above solution using bindings is the approach which is more Ember like ...
var dependency = Em.Object.create({
prop: []
});
App.View1 = Em.View.create({
dependency: dependency,
name: "Foo",
changeName: function () {
this.set("name", "Bar");
}.observes("dependency.prop.@each")
});
App.View2 = Em.View.create({
dependency: dependency,
name: "Foo",
changeName: function () {
this.set("name", "Bar");
}.observes("prop"),
propBinding: "dependency.prop.@each"
});
// Updating the 'prop' property of dependency.
dependency.get("prop").pushObject("An object.");
Upvotes: 2