Магистраль: несколько просмотров подписки на одно событие коллекции? Это плохая практика?

У меня есть вопрос, действительно основной материал, который я думаю, но:

Я видел только примеры с представлением коллекции и отдельным представлением, зависящим от обновляемой коллекции. Что делать, если у вас несколько просмотров, пытающихся подписаться на события коллекций, то есть reset, addOne, addAll и т.д.

Я пропустил какой-то момент о том, чтобы делать/не делать этого? У вас есть примеры этого? Это даже имеет смысл?

Любая информация МНОГО оценивается

    var Coll = Backbone.Collection.extend({
        model: SingleModel,
        url: 'service',
        initialize: function(){
            console.log('collection inited')

        }        

    });

    var SingleModel = Backbone.Collection.extend({});            

    var CollView = Backbone.View.extend({                
        el: 'ul',
        template: Handlebars.compile(someContainerTemplate),
        init: function(){
            _.bindAll(this, 'render', 'addAll', 'addOne');
            this.collection.bind("reset", this.addAll);

            this.collection.fetch();
        },
        render: function(){
            $(this.el).append(this.template())
        },

        addAll: function(){
            this.collection.each(this.addOne);
        },

        addOne: function(model){
            var view = new SingleView({ model: model })            
        }
    })

    var SingleView = Backbone.View.extend({
        tagName: "li",
        events: {
            "click .delete": "remove"                    
        },
        template: Handlebars.compile(someTemplateForSingleItem),  
        initialize: function() {
        _.bindAll(this,'render');

            this.model.bind('save', this.addOne);
            this.model.bind('destroy', removeEl);
        },

        remove: function(){
          this.model.destroy();  
        },

        removeEl: function(){
          $(this.el).remove();  
        },

        render: function() {
            var context = this.model.toJSON();
            return $(this.el).append(this.template(context));
        },       
    })


    // standard so far (excluding any bad practices), 
    // but what if you have another view dependent on 
    // say the number of length of the collection, and 
    // you want it to update if any single models are destroyed

    var HeaderView = Backbone.View.extend({
        tagName: "div#header",
        template: Handlebars.compile(someHeaderTemplate), 
        initialize: function() {
        _.bindAll(this,'render');

        this.model.bind('save', this.addOne);
        },

        render: function() {
            //assigning this collection length

            var context = this.collection.length;
            return $(this.el).append(this.template(context));
        },      
    });        

    var coll = new Coll();
    new CollView({ collection: coll });
    new HeaderView({ collection: coll});

Ответы

Ответ 1

То, что вы делаете, прекрасно и часть причины использования Backbone. Из Введение в базовую станцию ​​:

Всякий раз, когда действие пользовательского интерфейса вызывает изменение атрибута модели, модель запускает событие "изменения"; все представления, отображающие состояние модели, могут быть уведомлены об изменении,

Обратите внимание, что они говорят "все представления", а не "вид".

Одним из примеров нескольких представлений для одной коллекции будет чат-система. Предположим, у вас есть коллекция пользователей, которые находятся в сети; то у вас может быть один простой вид в заголовке, который отображает количество людей, которые находятся в сети, и другое представление (из той же коллекции), в котором перечислены пользователи:

var User = Backbone.Model.extend({});
var OnlineUsers = Backbone.Collection.extend({
    model: User
});

var CounterView = Backbone.View.extend({
    tagName: 'span',
    initialize: function() {
        _.bindAll(this, 'render');
        this.collection.on('add', this.render);
        // other interesting events...
    },
    render: function() {
        this.$el.text(this.collection.size());
        return this;
    }
});
var ListView = Backbone.View.extend({
    initialize: function() {
        _.bindAll(this, 'render');
        this.collection.on('add', this.render);
        // other interesting events...
    },
    render: function() {
        var html = this.collection.map(function(m) {
            return '<p>' + m.get('name') + '</p>';
        });
        this.$el.html(html.join(''));
        return this;
    }
});

Тогда у вас будет один экземпляр OnlineUsers, но оба экземпляра CounterView и ListView будут смотреть его. Когда люди выходят в Интернет или выходят в автономный режим, оба представления будут обновляться по желанию.

Простая демонстрация: http://jsfiddle.net/ambiguous/eX7gZ/

В приведенной выше ситуации ситуация звучит точно так же, как вы делаете, и это именно то, для чего нужна эталон. Хорошая работа.

Ответ 2

У нас была та же проблема. Нам нужно было использовать несколько шаблонов jQuery с уникальными внутренними событиями для каждой модели, не используя несколько видов держателей. Это решение, с которым мы столкнулись:

var myHolderView = Backbone.View.extend({
    el: '#views',
    render: function(){
        // This is because 'this' change inside the collection.each
        var $this = this;

        // If you want a wrapper template
        var wrapperHtml = $('#view-wrapper-template').tmpl();
        $this.$el.append(wrapperHtml);
        $wrapper = $this.$el.find('> div'); // If wrapper is a div


        $this.collection.each(function(model){
            // Render and append the viewA with internal events
            var viewA = new myViewA({model: model});
            viewA.render();

            // Use this to add the views content (viewA.el) to this views element ('#views')
            //$this.$el.append(viewA.el);

            // Use this to add the view content (viewA.el) to this views wrapper element ($wrapper)
            $wrapper.append(viewA.el);


            // Render and append the viewB with internal events
            var viewB = new myViewB({model: model});
            viewB.render();
            //$this.$el.append(viewB.el);
            $wrapper.append(viewB.el);


            // Add more views here...
        });
    }
});

Полный исходный и рабочий пример: http://jsfiddle.net/HLv5z/9/