在setElement上取消委派子视图事件
Marionette CompositeView undelegating childview events on setElement
我有一个marionette compositeview
,我用它来创建一个应用程序上的个人资料页面的项目列表。对于子视图,我从已经存在的ItemView
扩展。
当我在compositeview
onRender
函数中使用this.setElement(this.el.innerHTML)
时,子视图中设置的所有事件不再被触发,甚至更多,在浏览器的检查器工具的控制台上触发它们,什么也不做。
然而,当我不使用setElement
,容器div
被添加到我的标记,但现在所有的事件在子视图工作。
有人能帮我理解一下吗?
我使用的集合有一个自定义的clone
方法。
我正在使用一个全局集合,它在每次读取时更新并存储在缓存中。
当我实际实例化我的视图时,集合已经被使用,并且主layout
视图中的一个区域已经填充了一个类似于我想要渲染的项目列表。
我是这样实例化我的视图的:
var currentUser = Profile.get('username');
// Perform changes to global collection
Items.url = API + '/items/search?q=' + currentUser + '&size=20';
Items.parse = function (response) {
if (!response.results) {
return response;
} else {
return response.results;
}
};
Items.fetch(
{success: function (collection, response, options) {
this.listOfItems = new View.itemListProfilePage({
template: TemplIds.profilePagePostedItems,
parentClass: 'profile-cols',
collection: Items, // global collection
filterAttr: {user: currentUser},
isFiltered: true,
lazyLoad: true,
childViewContainer: '#profile-items',
childView: View.itemProfilePage.extend({
template: TemplIds.item
})
});
Backbone.trigger('main:show', this.listOfItems); //'main:show' is an event in layoutview which calls region.show
},
remove: false
});
My compositeview
:
View.itemListProfilePage = Marionette.CompositeView.extend({
collection: null, //original collection cloned later for filtering
fetch: null, //promise for fetched items
lazyView: null,
options: {
parentClass: '',
filterAttr: {},
isFiltered: false,
lazyLoad: false
},
initialize: function () {
this.stopListening(this.collection);
//Change collection property and re-apply events
this.collection = this.collection.clone(this.options.filterAttr, this.options.isFiltered);
this._initialEvents();
this.collection.reset(this.collection.where(this.options.filterAttr), {reset: true});
this.listenTo(Backbone, 'edit:profileItems', this.addEditClassToSection);
},
onRender: function () {
this.setElement(this.el.innerHTML, true);
},
onShow: function () {
if (this.options.parentClass) {
this.el.parentElement.className = this.options.parentClass;
}
},
addEditClassToSection: function (options) {
if ( options.innerHTML !== 'edit' ) {
this.el.classList.add('edit-mode');
} else {
this.el.classList.remove('edit-mode');
}
},
}
父ItemView
:
View.Item = Marionette.ItemView.extend({
model: null,
numLikes: null, //live set of DOM elements containing like counter
modalItem: null, //view class with further details about the item to be used within a modal
events: {
'click img.highlight': 'showModal'
},
initialize: function (options) {
var itemWithHeader; //extended item view class with header at the top and no footer
var addToCart;
//Set up all like-related events
this.listenTo(this.model, "change:numLikes", this.updateNumLikes);
this.listenTo(this.model, "change:liked", this.updateLiked);
//Set up the view classes to be used within the modal on click
itemWithHeader = View.ItemWithHeader.extend({
template: this.template,
model: this.model //TODO: move to inside itemDetails
});
itemAddToCart = View.ItemAddToCart.extend({
template: TemplIds.itemAddCart,
model: this.model //TODO: move to inside itemDetails
});
this.modalItem = View.ItemDetails.extend({
template: TemplIds.itemDetails,
model: this.model,
withHeader: itemWithHeader,
addToCart: itemAddToCart
});
},
onRender: function () {
var imgContainerEl;
var likeButtonEl;
//Get rid of the opinionated div
this.setElement(this.el.innerHTML);
this.numLikes = this.el.getElementsByClassName('num');
//Add the like button to the image
likeButtonEl = new View.LikeButton({
template: TemplIds.likeButton,
model: this.model
}).render().el;
this.el.firstElementChild.appendChild(likeButtonEl); //insert button inside img element
},
showModal: function (evt) {
var modalView = new View.Modal({
views: {
'first': {view: this.modalItem}
}
});
Backbone.trigger('modal:show', modalView);
},
});
我的列表中每个单独项目的itemView:
View.itemProfilePage = View.Item.extend({
events: _.extend({},View.Item.prototype.events, {
'click .delete-me': 'destroyView'
}
),
onRender: function () {
View.Item.prototype.onRender.call(this);
this.deleteButtonEl = new View.itemDeleteButton({
template: TemplIds.deleteButton
}).render().el;
this.el.firstElementChild.appendChild(this.deleteButtonEl);
},
destroyView: function (evt) {
this.model.destroy();
}
});
简短的回答是,您应该不使用setElement
。
Backbone特别使用额外的容器div
来限定/绑定视图的事件。当您使用setElement
时,您正在更改父元素的内容。由于您是在onRender
函数中执行此操作的,该函数在模板被渲染并且事件已经被绑定之后调用,因此您正在丢失事件绑定。
如果你打算使用Marionette和Backbone,正确的做法是期望并利用渲染视图时生成的"额外"div包装器。您可以通过在视图类上使用className
、id
和tagName
视图属性来控制"包装器"div的标记。
相关文章:
- 取消绑定主干视图事件
- 更改el属性时未激发主干视图事件
- angularjs中的SyncFusion树视图事件
- 在视图被替换后,主干视图事件未激发,然后放回页面上
- 主干视图事件绑定较晚
- 主干视图事件未触发 - 不知道原因
- Aurelia:调整大小/布局更改视图事件
- 主干 - 在模型更改时取消注册视图事件
- 在单页应用程序上实现Google Analytics页面视图事件的行为很奇怪
- 单击时呈现视图事件
- 木偶的复合视图事件未触发
- 主干,触发视图事件
- 主干视图事件仅在视图呈现后触发一次
- Dropzone.js AMD内部Backbone视图事件
- 提升骨干.js视图事件
- ExtjsMVC嵌套视图事件和异步函数
- 复选框和标签的主干视图事件处理程序
- 主干-从子视图触发父视图事件
- 骨干视图事件没有触发
- 在父元素上注册视图事件