集合委托事件

Collection Delegating Events

我有两个视图,一个是 ListView,一个是 ListRow 视图。 ListView 负责显示 UI 并处理搜索框上的事件。搜索方法在更改时触发,在 Backbone.search() 的帮助下,我得到了一组匹配模型。

但是,当我的 ListRow 视图呈现时(搜索后),事件未绑定到它们。我试图在实例化视图后立即在 filtered_events.each 块内的 ListView processSearch 方法中调用 view.delegateEvents() ,但这似乎根本没有帮助。下面是我的观点的源代码。

ListVIew.js

CheckinApp.Views.ListView = Backbone.View.extend({
properties: {
    list_title: '',
    event_id: null,
    list_type: ''
},

list_element: '.chk_list_main',

template: null,
collection: null,
el: '.content',

events: {
    "keyup #search": "processSearch",
    "change #search": "processSearch"
},

"processSearch": function(e) {
    var html = '';
    var search_string = $(e.currentTarget).val().toLowerCase();
    var filtered_events = this.collection.search(search_string, 'name');

    if(search_string == '') filtered_events = this.collection;

    console.log('searching tickets for \'' + search_string + '\' and found ' + filtered_events.length + ' matching tickets');

    filtered_events.each(function(model) {
        var list_template = (this.properties.list_type == 'event') ? '#list_row_event' : '#list_row_ticket';
        var view = new CheckinApp.Views.ListRow({"model": model, list_template: list_template});
        var rendered_view = view.render().el;
        html += '<div class=\'chk_list\'>' + $(rendered_view).html() + '</div>';
    }, this);

    if(html == '') {
        $(this.list_element).html($('#search_no_results').html());
    } else {
        $(this.list_element).html(html);
    }
    return this;
},

initialize: function(data) {
    if(this.properties.list_type == 'ticket' && data.event_id == null) {
        Backbone.history.navigate("#", true);
    }
    this.properties.list_title = data.list_title;
    this.properties.event_id = data.event_id;
    this.properties.list_type = data.list_type;

    if(data.list_type == 'event') {
        this.collection = new CheckinApp.Collections.Events();
    } else {
        this.collection = new CheckinApp.Collections.Tickets({"event_id": data.event_id});
    }

    this.template = _.template($('#listview').html())(this.properties);

    this.listenTo(this.collection, 'add', this.add_list_row);
    this.listenTo(this.collection, 'reset', this.add_all);
    this.collection.fetch();
},

render: function() {
    var logo = $('body').find('logo');
    var navigation = $('body').find('.navig');

    if(this.properties.list_type == 'event') {
        navigation.remove();
        logo.text(CheckinApp.session.user.brand);
    } else {
        logo.text(CheckinApp.session.user.current_venue);
    }

    $(this.el).html(this.template);
    return this;
},

add_list_row: function(model) {
    var list_template = (this.properties.list_type == 'event') ? '#list_row_event' : '#list_row_ticket';
    var view = new CheckinApp.Views.ListRow({"model": model, list_template: list_template});
    view.delegateEvents();
    var rendered_view = view.render().el;
    $(".chk_list_main").append(rendered_view);
},

add_all: function() {
    this.collection.each(this.add_list_row, this);
}
});

ListRow.js

CheckinApp.Views.ListRow = Backbone.View.extend({
tagName: "div",
className: "chk_list",
template: null,
events: {
    "click .checkd_in": "toggleCheckin",
    "click .undo_checkd_in": "toggleCheckin",
    "click .select_event, .txt_chk_text": "viewListsForEvent"
},

initialize: function(data) {
    this.model = data.model;

    this.template = _.template($(data.list_template).html());

    this.listenTo(this.model, 'change', this.render);
    this.listenTo(this.model, 'destroy', this.remove);
},

render: function() {
    (this.model instanceof CheckinApp.Models.Event) ? this.renderEventRow() : this.renderTicketRow();
    return this;
},

renderEventRow: function() {
    this.$el.html(this.template(this.model.attributes));
},

renderTicketRow: function() {
    if(this.model.get('checked_in') == 1) $(this.el).addClass('chk_undo_list');
    else $(this.el).removeClass('chk_undo_list');

    this.$el.html(this.template(this.model.attributes));
},

toggleCheckin: function(e) {
    e.preventDefault();
    this.model.save({
        "checked_in": (this.model.get('checked_in') == 0) ? "1" : "0"
    });
},

viewListsForEvent: function(e) {
    e.preventDefault();
    CheckinApp.session.user.current_venue = this.model.get("venue_name");
    CheckinApp.session.user.current_event = $(e.currentTarget).find('a').data('event');
    Backbone.history.navigate('guestlist', true);
}
});

我在 processSearch 方法中对视图进行字符串化,将其更改为以下修复了事件绑定问题。

    "processSearch": function(e) {
    var search_string = $(e.currentTarget).val().toLowerCase();

    var filtered_events = this.collection.search(search_string, 'name');

    if(search_string == '') filtered_events = this.collection;

    var results = [];
    filtered_events.each(function(model) {
        var item_row = new CheckinApp.Views.ListRow({"model": model, list_template: this.properties.list_template});
        results.push(item_row.render().el);
    }, this);

    if(results.length == 0) {
        $(this.list_element).html($('#search_no_results').html());
    } else {
        $(this.list_element).html(results);
    }
    return this;
},