DelegateEvents: дочерние элементы itemView не удаляются при удалении модели из коллекции

У меня есть collectionview ItineraryEditorView, который меняется местами в области макета и из нее. Один и тот же экземпляр collectionView заменяется с помощью region.show вместо того, чтобы каждый раз создавать новый экземпляр для collectioView. Метод рендеринга в коллекции вызывает метод delegateEvents().

    ItineraryEditorView = Marionette.CollectionView.extend({
    tagName: "div",
    emptyView: EmptyItineraryDayView,
    itemView: ItineraryDayView,
    initialize: function (options) {            
    },  
    render: function() {
        Marionette.CollectionView.prototype.render.apply(this);
        this.delegateEvents();
    },
});

Вид заменяется закрытием области:

plannerLayout.itineraryEditorRegion.close();

Обмен в представлении:

itineraryEditorView.delegateEvents();
plannerLayout.itineraryEditorRegion.show(itineraryEditorView);

Удаление модели выполняется путем прослушивания всплывающего события с itemView по collectionView (работает, здесь нет проблем)

itineraryEditorView.on("itemview:delete:day", function(childView, model)    {
    days.remove(model); //days coll is passed in to coll view on instance creation
    holiday.save();
});

Я ожидаю, что этого будет достаточно, чтобы обеспечить удаление/закрытие дочернего элемента itemViews в представлении коллекции при удалении модели из базовой коллекции дней. Я вижу, что коллекция фактически изменена и сохранена на сервере, однако представление коллекции не изменено. Этот сценарий, конечно, работает, когда представление коллекции заменяется в первый раз. Колл. представление обновляется после того, как я повторно посещу другую вкладку и вернусь на эту вкладку (таким образом, вся коллекция отображается - подтверждение изменения/удаления)

Каков наилучший способ обойти эту проблему? Если я воссоздаю экземпляр представления коллекции, это приводит к потере других дескрипторов в коде.


person Nilesh Kale    schedule 30.08.2013    source источник
comment
Тот факт, что вы вызываете delegateEvents вручную, вызывает у меня подозрения. Вы повторно используете свой вид после закрытия региона?   -  person Chris Camaratta    schedule 30.08.2013
comment
@chris да, я повторно использую представления.   -  person Nilesh Kale    schedule 31.08.2013
comment
Marionette не предназначена для повторного использования закрытых представлений. Этот поток может вам помочь: stackoverflow.com/questions/17920499 /   -  person Chris Camaratta    schedule 31.08.2013


Ответы (1)


Нет необходимости вызывать delegateEvents вручную — Backbone делает это в конструкторе представления. Когда вы закроете регион, регион закроет ваше представление, удаляя все внутренние ссылки и отвязывая все события, подготавливая его к сборке мусора. После того, как представление было close() создано, его нельзя использовать снова. Решение вашей проблемы должно состоять в том, чтобы new создать еще один экземпляр вашего ItineraryEditorView и передать его в регион на show.

Кроме того, нет необходимости вызывать region.close() перед вызовом region.show(view); первое, что show делает, это close() текущий вид, если он есть. Моя рекомендация изменить ваш код следующим образом:

ItineraryEditorView = Marionette.CollectionView.extend({
    // tagName: "div", // <-- unnecessary as written - default tag

    emptyView: EmptyItineraryDayView,

    itemView: ItineraryDayView

    // this empty override is unnecessary as written - recommend removing it
    // initialize: function (options) {           
    // },

    // this override is unnecessary as written - remove it:
    // render: function() {
    //     Marionette.CollectionView.prototype.render.apply(this);
    //     this.delegateEvents();
    // },
});

...

// plannerLayout.itineraryEditorRegion.close(); <-- delete this line; it's not needed
// itineraryEditorView.delegateEvents();        <-- ditto

ОТРЕДАКТИРОВАНО ИЗ ИСХОДНОГО СООБЩЕНИЯ

// define a delegate to handle events shared across multiple instances of the view:
function handleDeleteChild(childView, model) {
    days.remove(model); //days coll is passed in to coll view on instance creation
    holiday.save();
});

// create the ItineraryEditorView
// NOTE: As written this will likely conflict with your current code;
//       update as required
var itineraryEditorView = new ItineraryEditorView(options);

// bind event listeners to it
itineraryEditorView.on("itemview:delete:day", handleDeleteChild);

// show it
plannerLayout.itineraryEditorRegion.show(itineraryEditorView);
person Chris Camaratta    schedule 30.08.2013
comment
Спасибо за ответ. Однако, если я использую новые экземпляры представления, другие события приложения, а именно. view.on(myevent) перестает работать. Я не могу понять причину того же, но я думаю, это отдельный вопрос? Единственный способ обойти это - не использовать this.trigger из представления, а вместо этого передать экземпляр макета для просмотра и использования layout.trigger !? - person Nilesh Kale; 31.08.2013
comment
Я попробовал приведенный выше код, удалив событие делегата, и события не работают должным образом. Они работают после явного вызова delegateEvents. - person Nilesh Kale; 31.08.2013
comment
Если вы разработали свое приложение, думая, что можете повторно использовать закрытые представления, то эти симптомы имеют смысл. Операцию close следует рассматривать как деструктор (например, C# или Java) для представлений Marionette. Как только представление закрыто, любые внешние ссылки, которые вы сделали на него, должны быть удалены, а любые прослушиватели событий должны быть отвязаны. Поскольку вместо него вы создаете новое представление, вам потребуется повторно привязать все прослушиватели событий, ранее прикрепленные к старому. - person Chris Camaratta; 31.08.2013
comment
Я изменил код, чтобы показать, как повторно связать событие delete, определенное в вашем вопросе; аналогичные изменения могут потребоваться в другом месте вашего приложения. - person Chris Camaratta; 31.08.2013
comment
Код, который вы изменили, является хорошим вариантом для подражания (в краткосрочной перспективе). Спасибо, что поделились этим. Тем не менее, это означает, что для будущего приложения может быть лучше потратить время сейчас, чтобы переписать некоторый код и просто использовать новые представления, независимо от того, разрешают или запрещают следующие версии marrionette повторное использование представлений. - person Nilesh Kale; 02.09.2013
comment
Рад, что смог помочь! :) На моем месте я бы потратил время на переработку приложения, предполагая, что Marionette никогда не будет поддерживать повторное использование закрытых представлений. Эта статья немного устарела, но в ней рассказывается история возникновения операции close и проблемы, которые она решает: lostechies.com/derickbailey/2011/09/15/ - person Chris Camaratta; 02.09.2013