Как я могу всплывать событиями во вложенных коллекциях Backbone?

У меня есть приложение Backbone, которое использует вложенные коллекции (по крайней мере, я так думаю, что они называются).

В моем конкретном случае есть вкладки и вложенные вкладки, и каждая вкладка (модель) содержит набор вложенных вкладок (модели).

Для тех, кто более знаком с кодом, я напишу ниже свои модели и коллекции, а также то, как вложенные вкладки вложены в модель вкладок:

// Subtab Model
var Subtab = Backbone.Model.extend({
    defaults: { label: undefined }
});

// Subtabs Collection
var Subtabs = Backbone.Collection.extend({
    model: Subtab
});

// Tab Model
var Tab = Backbone.Model.extend({
    defaults: { label: undefined, subtabs: new Subtabs}
});

// Tabs Collection
var Tabs = Backbone.Collection.extend({
    model: Tab
});

Теперь, когда я изменяю атрибут вкладки, он запускает событие изменения в модели Tab, а также в коллекции Tabs (вполне нормально, не так ли?), Но когда я изменяю атрибут вложенной вкладки, он запускает событие изменения в модели Subtab и Subtabs коллекция (это тоже нормально), но она не поднимается до модели Tab (и до коллекции Tabs).

По крайней мере, я думаю, это должно быть, потому что коллекция внутри модели была изменена, и поэтому модель была изменена (но, возможно, я ошибаюсь и не понимаю).

Есть предложения о том, как добиться такого поведения с помощью Backbone?


person Chris X    schedule 06.04.2013    source источник
comment
запускать событие вручную при его получении   -  person Cory Danielson    schedule 07.04.2013
comment
@CoryDanielson Я представил, что событие нужно запускать «вручную», но это не сработало, я получил RangeError: Превышен максимальный размер стека вызовов.   -  person Chris X    schedule 07.04.2013
comment
Вы что-то делаете с setTimeout? Это не та ошибка, которую я когда-либо получал при использовании Backbone   -  person Cory Danielson    schedule 07.04.2013
comment
@CoryDanielson Нет, совсем нет!   -  person Chris X    schedule 08.04.2013
comment
Я никогда не видел, чтобы ошибка стека вызовов происходила из-за чего-то неасинхронного ... что-то асинхронное должно происходить ... событие вызывает кучу вызовов ajax? у вас одновременно работает setInterval? Насколько велика коллекция? Что делает this.subtabsChanged, о котором вы упомянули в другом комментарии?   -  person Cory Danielson    schedule 08.04.2013
comment
@ChrisX Обычно превышение максимального размера стека вызовов является сильным признаком того, что у вас происходит бесконечная рекурсия. Может ли слушатель изменений в вашей внешней модели делать что-то, что вызовет изменения во внутренней модели? Тогда события изменения будут повторяться вечно ...   -  person peterflynn    schedule 11.12.2013


Ответы (1)


Событие change запускается Backbone, когда атрибут изменяется через set. Затем событие также запускается в коллекции, как вы видели. Но значение вашего атрибута subtabs вообще не меняется, это все тот же объект, который вы создали в defaults. Если бы вы использовали tab.set('subtabs', new Subtabs);, вы бы получили change:subtabs событие, но вы не хотите этого делать.

Я думаю, вам нужно будет что-то сделать в своем коде, чтобы вызвать новое событие в вашей модели вкладки.

// Tab Model
var Tab = Backbone.Model.extend({
    defaults: { label: undefined, subtabs: new Subtabs},
    initialize: function(){
        // listen for change in subtabs collection.
        this.get('subtabs').on('change', this.subtabsChanged, this);
    },
    subtabsChanged: function(model) {
        // trigger new event.
        this.trigger('subtab:change', this, model);
    }
});

Затем вы можете прослушать событие:

tabs.on('subtab:change', function(tab, subtab) { 
    console.log(tab.get('label'));
    console.log(subtab.get('label'));
});

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

tab.get('subtabs').on('change', function(model){
    // do something with model, which is a Subtab.
});

РЕДАКТИРОВАТЬ: http://jsfiddle.net/phoenecke/DvHqH/1/

person Paul Hoenecke    schedule 06.04.2013
comment
Основываясь на вашем ответе и с некоторыми изменениями в вашем коде, мне удалось вызвать исходное событие change в модели. Я делал неправильную привязку события change без какого-либо контекста this.get('subtabs').on('change', this.subtabsChanged, this);, и я получал сообщение об ошибке RangeError: Превышен максимальный размер стека вызовов. Итак, this - это ключ. - person Chris X; 07.04.2013
comment
что делает this.subtabsChanged? - person Cory Danielson; 08.04.2013
comment
@CoryDanielson Запускает событие на вкладке, когда что-то в дочерней коллекции вложенных вкладок изменилось ... - person Paul Hoenecke; 08.04.2013
comment
@PaulHoenecke, извините, я спрашивал Криса X, пытаясь понять, почему он получает RangeError - person Cory Danielson; 08.04.2013
comment
@CoryDanielson, как видите, .subtabsChanged является обработчиком события изменения, когда оно запускается коллекцией вложенных вкладок. Этот обработчик запускает настраиваемое событие subtab:change для вкладки (модели). - person Chris X; 08.04.2013
comment
@CoryDanielson. Обновлено с помощью jsFiddle. В этом коде нет ошибки размера стека. - person Paul Hoenecke; 08.04.2013
comment
обратите внимание, listenTo() может быть предпочтительнее on(). backbonejs.org/#Events-listenTo - person ericsoco; 08.07.2013
comment
re: Мне интересно, почему вы слушаете свою коллекцию вкладок для изменения вложенных вкладок, одним из примеров может быть случай, когда у вас есть одно представление, представляющее содержимое коллекции вкладок и вложенных вкладок ... - person ericsoco; 08.07.2013