Bubbling events in nested Backbone (Marionette) Models / Collections

前端 未结 1 1194
粉色の甜心
粉色の甜心 2020-12-07 05:29

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 M

相关标签:
1条回答
  • 2020-12-07 06:00

    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');
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>

    0 讨论(0)
提交回复
热议问题