Bubbling events in nested Backbone (Marionette) Models / Collections

匿名 (未验证) 提交于 2019-12-03 01:26:01

问题:

We have a large Marionette App, that uses Backbone.trackit to monitor unsaved changes in our Models.

We now have some nested models, in fact we have a Model, with a Collection of Models, that contain a Collection of Models.

trackit doesn't support the top level model being marked as 'dirty' when the child models change - due to backbone not bubbling these change events.

I know we could manually monitor these change events, but Im looking for a generic solution.

Has anyone had any experience of the following libs or any other solutions for this?

  1. backbone-deep-model
  2. Backbone Associations events
  3. Custom Backbone.Model.set override that bubbles change events

The immediate requirement is to get trackit working with nested events - but I cant find any branches to trackit that add this.

So I was wondering if anyone has approached this, or used the above libs in conjunction with trackit?

Ideally, if a library would trigger a standard 'change' event all the way up the chain, then trackit would just pick up on this and start working.

so, if model.countries[3].regions[4].name changed, a change:countries event would be triggered on model. Thus if the model had trackit enbaled, it would all just work!

回答1:

The events from models inside a collection already bubbles to the collection by default. So that's one thing solved and we just need to bubble events from a collection or another model inside a model.

One problem I see with bubbling events as-is up the hierarchy is that you then get false positive when you want to listen to that specific collection or model.

A way to avoid that is to namespace events that are bubbling up, but that may not work with trackit.

A simple implementation of a model that enables bubbling up events of arbitrary collections or other nested models:

var BubblingModel = Backbone.Model.extend({     /**      * Bubbles up any event triggered by 'object'.      * @param {Backbone.Events} obj which implement the Backbone Events.      * @param {String} key optional namespace name, default to 'nested'.      */     addNested: function(obj, key) {         return this.listenTo(obj, 'all', function() {             arguments[0] = (key || 'nested') + ':' + arguments[0];             this.trigger.apply(this, arguments);         });     },     removeNested: function(obj) {         return this.stopListening(obj);     } }); 

and to use it:

var collection = new Backbone.Collection(),     model = new BubblingModel(); model.addNested(collection, 'optional-key'); 

Any events from collection will be prefixed by its optional key or by the default nested string. A change:myAttribute event triggered by collection would be:

"optional-key:change:myAttribute" 

Proof of concept with simple tests:

// The simple implementation var BubblingModel = Backbone.Model.extend({     /**      * Bubbles up any event triggered by 'object'.      * @param {Backbone.Events} obj which implement the Backbone Events.      * @param {String} key optional namespace name, default to 'nested'.      */     addNested: function(obj, key) {         return this.listenTo(obj, 'all', function() {             arguments[0] = (key || 'nested') + ':' + arguments[0];             this.trigger.apply(this, arguments);         });     },     removeNested: function(obj) {         return this.stopListening(obj);     } });  // Setting up a test with multiple nesting var model5 = new Backbone.Model(),     model4 = new Backbone.Model(),     model3 = new BubblingModel({ model: model4 }),     col2 = new Backbone.Collection([model3]),     model2 = new BubblingModel({ col: col2 }),     col1 = new Backbone.Collection([model2]),     model1 = new BubblingModel({ col: col1 });  // Set which you want to bubble up. model3.addNested(model4, 'model3-nested-model'); model2.addNested(col2, 'model2-nested-col')     .addNested(model5); model1.addNested(col1, 'model1-nested-col');  // listen from any model down the chain Backbone.listenTo(model2, 'all', function(eventName) {     console.log("model2:", eventName); }); Backbone.listenTo(model1, 'all', function(eventName) {     console.log("model1:", eventName); });  // trigger default or custom events model3.set('test', 1); model3.trigger('model3'); model4.trigger('model4'); model5.trigger('model5');
  


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!