9

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

在我的例子中:

personChangedfirstname当orlastname改变时被调用:

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

2 回答 2

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所有属性,并且每次任何属性更改时都会调用该函数。然而,由于观察者被急切地解雇 [1],该函数应该是幂等的,而示例中的函数不是。下一个解决方案通过让观察者变得懒惰来解决这个问题。contentpersonChangedpersonChanged

解决方案 2

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

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');
    }
});

这里唯一的变化是实际的观察者函数现在只在Ember Run 循环结束时被调用,这可能是您正在寻找的行为。

其他注意事项

这些解决方案使用ObjectProxy而不是在对象本身上定义观察者,以避免设置虚假的观察者(在诸如 、 等属性上initwillDestroy要观察的属性的显式列表

可以将此解决方案扩展为开始观察动态属性,方法是setUnknownProperty在每次将键添加到时重写代理以添加观察者content。将willDestroy保持不变。

参考

[1] 多亏了 Asyn Observers,这可能很快就会改变

于 2012-12-29T18:26:47.597 回答
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/

于 2012-12-29T07:33:56.807 回答