Backbone.Collection.reset() => дочернее представление не синхронизировано с родительским
У меня есть список предметов. Они хранятся в магистральной страничной коллекции.
Они отображаются так
| --- item1 --------------------------- |
| --- item2 --------------------------- |
| --- item3 --------------------------- |
| --- item4 --------------------------- |
| --- Item5 --------------------------- |
| --- item6 --------------------------- |
| --- ст.7 --------------------------- |
<< 1,2,3... конец >>
Пользователь может щелкнуть отдельный элемент, чтобы открыть подробный вид на отдельной странице. В подробном представлении слушатели инициализируются при его создании. Эти слушатели связаны с моделью предмета.
Поскольку подробный вид огромен, я кеширую его в DOM, переключая видимость. Последующее нажатие на элемент переключит кешированное представление.
------ вот проблема -----
Когда список элементов переключается на другую страницу, коллекция сбрасывается (по страницам). И все модели, ранее сохраненные в коллекции, разыменовываются, и создается новый набор моделей. Таким образом, после того, как страница переключается вперед и назад, ранее открытый элемент имеет другую копию себя, хранящуюся в коллекции. Поэтому, когда я изменяю имя элемента в подробном представлении (в кэше представления), имя в списке элементов не изменяется.
Мнения не синхронизированы! потому что они ссылаются на разные модели.
Не уверен, если кто-то еще сталкивался с этим раньше. Если вы это сделаете, пожалуйста, поделитесь со мной, как вы решаете это.
Спасибо большое.
1 ответ
Самый простой способ сохранить свежую ссылку между элементами представления списка и соответствующим подробным видом при смене страницы - это повторно отобразить подробный вид. Но я предполагаю, что эти варианты не приемлемы в рамках вашего проекта.
Что я часто делаю, когда у меня возникает задача формирования отношений внутри логически отдельных представлений, это использование слушателей. Пока представления разделяют уникальный идентификатор (например, они оба разделяют модель или, по крайней мере, идентичные идентификаторы модели), я всегда могу отправить сообщение, которое достигнет интересующего меня представления.
Для этого вам понадобится централизованный концентратор событий, который с помощью Backbone легко создать. В некоторой подходящей глобальной переменной (как, например, MyApp
) мы просто делаем:
MyApp.EventBus = _.extend({}, Backbone.Events);
Настройте подробный вид
На подробном представлении инициализировать функцию, я бы бросил этот слушатель,
initialize: function () {
// Listen to a toggle visibility on this view
this.listenTo(MyApp.EventBus, 'detail-view:toggle-view', toggleView);
},
toggleView: function (id) {
if (this.model.id == id) {
// Show this view if I have the passed id
this.$el.show()
// Notify the parent list item view that its detail view exists
MyApp.EventBus.trigger('detail:view:exists', true);
} else {
// Hide all other views
this.$el.hide();
}
},
changeName: function () {
// logic that parses DOM user input to
// local variable name
// We now trigger an event 'detail-view:change:name', and we send as
// parameters our model's id and the new name
MyApp.EventBus.trigger('detail-view:change:name', this.model.id, name);
}
Настройка вида элемента списка
Представление элемента списка захочет прослушать изменение имени (или любое другое свойство модели в подробном представлении, о котором вы хотите, чтобы элемент списка знал). Поэтому мы настроим обработчик для события 'detail-view:change:name'.
Мы также хотим подключить наш обработчик кликов, чтобы переключить видимость подробного представления элемента списка. Сложнее всего обработать событие, когда представление еще не было отрисовано (я предполагаю, что вы лениво загружаете подробный вид). Поэтому мы создали второго слушателя для detail:view:exists
событие подробный вид срабатывает, когда он ловит detail-view:toggle-view
событие. Если мы не слышим detail:view:exists
событие из целевого подробного представления своевременно (я использую 100 мс, но вы можете поэкспериментировать с этим в соответствии с вашими потребностями), затем мы визуализируем представление.
initialize: function () {
// Listen to when the detail associated with this list item changes
// the the list item name
this.listenTo(MyApp.EventBus, 'detail-view:change:name', onNameChange);
// Set a property in this view if its detail view exists
this.listenTo(MyApp.EventBus, 'detail:view:exists',
_.bind(function () { this.detailViewExists = true; }, this));
// Create a debounced function that tests whether this view's
// detail view exists
_.debounce(_.bind(this.handleViewState, this), 100);
},
events {
click: 'toggleDetailView'
},
toggleDetailView: function (id) {
MyApp.EventBus.trigger('detail-view:toggle-view', this.model.id);
this.handleViewState();
},
// Debounced function that will wait 100ms asynchronously for the
// detail view to respond. If the detailViewExists bit is not set to true
// then we assume the view does not exist and we render it
handleViewState: function () {
if (!this.detailViewExists)
// The view does not exist, render and attach the view
// Set the bit to false to allow testing in the event that the detail view
// is destroyed in the future
this.detailViewExists = false;
},
changeName: function (id, newname) {
if (this.model.id == id) {
// Change the name of this list item view
this.$('.item-name').text(newname);
}
Вынос
Теперь ссылка между этими двумя разными взглядами является общим уникальным идентификатором. Поскольку эти два идентификатора по своей конструкции уникальны по своей области действия и не должны изменяться, и при условии, что подробное представление было визуализировано и присоединено к DOM, то независимо от отображения его состояния представление элемента списка всегда сможет обмениваться данными. с его подробным видом.