これはObjectProxy
、要件に応じて、2つのフレーバーを使用して可能です。どちらのアプローチも、オブザーバーが呼び出されるタイミングと回数だけが異なり、どちらもに依存してい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]、関数はべき等である必要がありますが、この例の関数はそうではありません。次の解決策は、オブザーバーを怠惰にすることでこれを修正します。content
personChanged
personChanged
解決策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
、オブジェクト自体にオブザーバーを定義する代わりに、スプリアスオブザーバー(、などのプロパティ)または監視するプロパティの明示的なリストを設定しないようにするためにinit
使用willDestroy
します。
setUnknownProperty
このソリューションは、キーがに追加されるたびにオブザーバーを追加するためにプロキシでをオーバーライドすることにより、動的プロパティの監視を開始するように拡張できますcontent
。はwillDestroy
同じままになります。
参照
[1]AsynObserversのおかげでこれはすぐに変更される可能性があります