简体   繁体   English

骨干模板内的DOM元素不响应事件

[英]DOM element inside backbone template doesn't respond to event

I have 2 Backbone views. 我有2个Backbone视图。 One view (AppView) represents the entire collection and when it fetches it, parses the collection and generates the individual model views for each model in the collection. 一个视图(AppView)表示整个集合,当它获取它时,解析集合并为集合中的每个模型生成单独的模型视图。

The one issue I'm having is when the model views are created, they no longer respond to my click event which is a method of the model view. 我遇到的一个问题是,在创建模型视图时,它们不再响应我的click事件,这是模型视图的一种方法。 In the model view, if I replace tagName with el , the event can fire, however it fires for every single model in the collection instead of the individual model. 在模型视图中,如果我用el替换tagName ,则事件可以触发,但是它会针对集合中的每个模型而不是单个模型触发。

I think it has something to do with the events being untied from the template on load but I can't figure out how to tie back in, or generate the template without untying them. 我认为这与在加载时从模板中解开的事件有关,但我无法弄清楚如何绑定,或生成模板而不解开它们。

// INDIVIDUAL ITEMS WITHIN THE VIEW
ModelView = Backbone.View.extend({
// el: '#item-block', // click event shows an action for all 20 models within the collection
tagName: '.item-wrapper', // click event not heard
template: _.template($('#template').html()),
events: {
    'click.details': 'fireModel', // .details is a div inside of the template
},
initialize: function () {

    // _.bindAll(this, 'render', 'fireModel');
    this.render();

},
render: function() {

    var holder   = $('#item-block');

    if(this.model.attributes.caption == null) {
        var cloned = _.clone(this.model.get('caption'));

        cloned = {};
        cloned.text = '';

        this.model.set('caption', cloned);
    }

    holder.append(this.template(this.model.toJSON()));

    // this.delegateEvents()

    // return this;

},
fireModel: function(e) {

    console.log('clicked');

},
});


// COLLECTION GENERATES INDIVIDUAL MODEL VIEW
AppView = Backbone.View.extend({
el: '#social',
events: {
    'click #load-more': 'fetchCollection'
},
initialize: function() {
    this.collection = new MyCollection();

    this.collection.on('sync', this.render, this);

    this.collection.fetchData();
},
render: function() {

    for (var i = 0; i < this.collection.cache.models.length; i ++) {
        modelView = new ModelView({model: this.collection.cache.models[i]});
    }

},
fetchCollection: function() {
    this.collection.fetchData();
},

});

// CREATE NEW COLLECTION
app = new AppView

Here's the template 这是模板

<section id="social">

<div id="item-block">   
</div>

<div id="load-more">Load More</div>

</section>

<script type="text/template" id="template">

<div class="item-wrapper">
    <div class="details">
        <span class="caption"><%= caption.text %></span>
    </div>
    <div class="image">
        <img src="<%= images.standard_resolution.url %>" data-id="<%= id %>">
    </div>
</div>

</script>

<!-- JS LIBS AND BACKBONE SCRIPTS HERE -->

A few things to note: 有几点需要注意:

First , I want to mention that tagName property of Backbone.View should be the name of the HTML element ( div , ul , ...., by default it's div ). 首先 ,我想提一下Backbone.View tagName属性应该是HTML元素的名称( divul ,....,默认情况下是div )。

Second , you attaching your modelView (childView) to appView from model view. 其次 ,从模型视图将modelView(childView)附加到appView。 It's can be implemented in a better manner. 它可以以更好的方式实施。 Move that logic to the appView (parentView). 将该逻辑移动到appView(parentView)。

Third , use Underscore.js 's each method instead of for loop. 第三 ,使用Underscore.js的each方法而不是for循环。

Use documentFragment to cache the childViews and append it at once, instead of one by one (performance optimization). 使用documentFragment缓存childViews并立即追加它,而不是逐个追加(性能优化)。

And the final look should be: 最后的样子应该是:

ModelView = Backbone.View.extend({
    template: _.template($('#template').html()),
    attributes: {
       'class': 'item-wrapper'
    },
    events: {
        'click .details': 'fireModel', // .details is a div inside of the template
    },
    initialize: function () {
        this.render();
    },
    render: function() {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    fireModel: function(e) {
        console.log('clicked');
    },
});


// COLLECTION GENERATES INDIVIDUAL MODEL VIEW
AppView = Backbone.View.extend({
el: '#social',
events: {
    'click #load-more': 'fetchCollection'
},
initialize: function() {
    this.collection = new MyCollection();
    this.collection.on('sync', this.render, this);
    this.collection.fetchData();
},
render: function() {
    var buffer = document.createDocumentFragment();
    this.collection.each(function(model){
        if(model.attributes.caption == null) {
            // do your checks here
        } 
        var itemView = new ModelView({model: model});
        buffer.appendChild(itemView.render().el); // adding it to buffer   
    });

    this.$el.append(buffer); // appending all at once
}
});

// CREATE NEW COLLECTION
app = new AppView();

Update 更新

In this way any time collection's sync event fired, it will append new itemViews to the parentView, so be sure to add checks there. 通过这种方式,任何时间集合的sync事件都会被触发,它会将新的itemViews附加到parentView,所以一定要在那里添加检查。

Maybe you should insert some space between the event and the selector. 也许你应该在事件和选择器之间插入一些空格。

try 尝试

'click .details': 'fireModel'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM