Ember.js:观察所有对象属性

时间:2012-12-29 00:16:54

标签: ember.js

我想观察对象属性的所有更改 在下面的示例中,我希望personChanged观察者通知firstname或lastname更改。
但我想在所有对象属性上应用泛型(使用Ember.keys()??) 如何用更通用的东西替换'firstname','lastname'?

在我的例子中:

personChangedfirstname更改时调用

lastname

 App.MyObject: Ember.Object.create({
   firstname: 'first',
   lastname: 'last',
   personChanged: Ember.observer(function() {
            console.log("person changed");
   }, 'firstname', 'lastname') 
 })

2 个答案:

答案 0 :(得分:8)

根据您的要求,可以使用两种版本的ObjectProxy。这两种方法的不同之处仅在于观察者被调用的时间和次数,并且它们都依赖于Ember.keys

两种解决方案的HTML都是一样的。

<强> HTML

<script type="text/x-handlebars" data-template-name="app">
    Name: {{App.MyObject.firstname}} {{App.MyObject.lastname}}

    <ul>
    {{#each App.List}}
        <li>{{this}}</li>
    {{/each}}
    </ul>
</script>

解决方案1 ​​

JsFiddle:http://jsfiddle.net/2zxSq/

<强>的Javascript

App = Em.Application.create();

App.List = [];

App.MyObject = Em.ObjectProxy.create({
    // Your Original object, must be defined before 'init' is called, however.
    content: Em.Object.create({
        firstname: 'first',
        lastname:  'last'
    }),


    // These following two functions can be abstracted out to a Mixin
    init: function () {
        var self = this;
        Em.keys(this.get('content')).forEach(function (k) {
            Em.addObserver(self.get('content'), k, self, 'personChanged')
        });
    },

    // Manually removing the observers is necessary.
    willDestroy: function () {
        var self = this;
        Em.keys(this.get('content')).forEach(function (k) {
            Em.removeObserver(self.get('content'), k, self, 'personChanged');
        });
    },

    // The counter is for illustrative purpose only
    counter: 0,
    // This is the function which is called.
    personChanged: function () {
        // This function MUST be idempotent.
        this.incrementProperty('counter');
        App.List.pushObject(this.get('counter'));
        console.log('person changed');
    }
});

App.ApplicationView = Em.View.extend({
    templateName: 'app'
});

// Test driving the implementation.
App.MyObject.set('firstname', 'second');
App.MyObject.set('lastname',  'last-but-one');

App.MyObject.setProperties({
    'firstname': 'third',
    'lastname' : 'last-but-two'
});

在初始化MyObject时,会观察content对象上存在的所有属性,并且每次有任何属性时都会调用函数personChanged变化。但是,由于观察者急切地被解雇[1],函数personChanged应该是idempotent,而示例中的函数不是http://jsfiddle.net/2zxSq/1/。下一个解决方案通过使观察者变得懒惰来解决这个问题。

解决方案2

JsFiddle:the end of the Ember Run loop

<强>的Javascript

App.MyObject = Em.ObjectProxy.create({
    content: Em.Object.create({
        firstname: 'first',
        lastname:  'last'
    }),


    init: function () {
        var self = this;
        Em.keys(this.get('content')).forEach(function (k) {
            Em.addObserver(self, k, self, 'personChanged')
        });
    },

    willDestroy: function () {
        var self = this;
        Em.keys(this.get('content')).forEach(function (k) {
            Em.removeObserver(self, k, self, 'personChanged');
        });
    },

    // Changes from here 
    counter: 0,
    _personChanged: function () {
        this.incrementProperty('counter');
        App.List.pushObject(this.get('counter'));
        console.log('person changed');
    },

    // The Actual function is called via Em.run.once
    personChanged: function () {
        Em.run.once(this, '_personChanged');
    }
});

这里唯一的变化是现在只在explicit list of properties to observe调用实际的观察者函数,这可能是你正在寻找的行为。

其他说明

这些解决方案使用ObjectProxy而不是在对象本身上定义观察者,以避免设置虚假观察者(在initwillDestroy等属性上)或{{3 }}

此解决方案可以扩展为通过覆盖代理上的setUnknownProperty来开始观察动态属性,以便在每次将密钥添加到content时添加观察者。 willDestroy将保持不变。

<强> 参考

[1]由于Asyn Observers

,这可能会很快改变

答案 1 :(得分:2)

你在那里使用内联观察者是正确的,但你只是有一些语法错误。然而,使用关键词observes更简单。所以我在下面稍微调整了你的例子。

App.MyObject: Ember.Object.create({
    firstname: 'first',
    lastname: 'last',
    personChanged: function() {
        //firstname or lastname changed
    }.observes('firstname','lastname')
});

注意:我在属性

周围加上引号

来源: http://emberjs.com/guides/object-model/observers/