集合委托事件
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;
},
我有两个视图,一个是 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;
},