Javascript 主干:在视图上显示集合中每个模型的验证错误
我正在开发一个主干应用程序,允许用户添加多个项目 这是我的型号:Javascript 主干:在视图上显示集合中每个模型的验证错误,javascript,backbone.js,backbone.js-collections,Javascript,Backbone.js,Backbone.js Collections,我正在开发一个主干应用程序,允许用户添加多个项目 这是我的型号: //Model var Item = Backbone.Model.extend({ defaults: { part1: 'hello', part2: 'world' }, validate: function (attr, options) { var error = ''; //console.log(attr);
//Model
var Item = Backbone.Model.extend({
defaults: {
part1: 'hello',
part2: 'world'
},
validate: function (attr, options) {
var error = '';
//console.log(attr);
if(attr.part2 == "world1"){
this.trigger('err:world1');
error = 'world 1 error';
}
if(attr.part2 == "world3"){
this.trigger('err:world3');
error = 'world 3 error';
}
}
});
//Collection
var List = Backbone.Collection.extend({
model: Item,
validateModels: function() {
var cloneCollection = this.clone();
var errorModels = this.filter(function(m) {
if (!m.isValid()) {
return m;
}
});
// cloneCollection.remove(errorModels);
return cloneCollection;
}
});
收藏:
//Model
var Item = Backbone.Model.extend({
defaults: {
part1: 'hello',
part2: 'world'
},
validate: function (attr, options) {
var error = '';
//console.log(attr);
if(attr.part2 == "world1"){
this.trigger('err:world1');
error = 'world 1 error';
}
if(attr.part2 == "world3"){
this.trigger('err:world3');
error = 'world 3 error';
}
}
});
//Collection
var List = Backbone.Collection.extend({
model: Item,
validateModels: function() {
var cloneCollection = this.clone();
var errorModels = this.filter(function(m) {
if (!m.isValid()) {
return m;
}
});
// cloneCollection.remove(errorModels);
return cloneCollection;
}
});
我允许用户从视图中添加/删除项目,如下所示:
//Item View
var ItemView = Backbone.View.extend({
tagName: 'li', // name of tag to be created
events: {
'click span.swap': 'swap',
'click span.delete': 'remove'
},
initialize: function(){
_.bindAll(this, 'render', 'unrender', 'swap', 'remove'); // every function that uses 'this' as the current object should be in here
this.model.bind('change', this.render);
this.model.bind('remove', this.unrender);
this.model.on('err:world1', this.world1Err);
this.model.on('err:world3', this.world3Err);
},
render: function(){
$(this.el).html('<span style="color:black;">'+this.model.get('part1')+' '+this.model.get('part2')+'</span> <span class="swap" style="font-family:sans-serif; color:blue; cursor:pointer;">[swap]</span> <span class="delete" style="cursor:pointer; color:red; font-family:sans-serif;">[delete]</span> <span class="error" style="color:red; font-family:sans-serif;"></span>');
return this; // for chainable calls, like .render().el
},
unrender: function(){
$(this.el).remove();
},
swap: function(){
var swapped = {
part1: this.model.get('part2'),
part2: this.model.get('part1')
};
this.model.set(swapped);
},
remove: function(){
this.model.destroy();
},
world1Err: function(){
alert('World 1 Err');
//console.log(this);
},
world3Err: function(){
alert('World 3 Err');
}
});
//Composite View
var ListView = Backbone.View.extend({
el: $('body'), // el attaches to existing element
events: {
'click button#add': 'addItem',
'click button#save': 'saveCollection'
},
initialize: function(){
_.bindAll(this, 'render', 'addItem', 'appendItem'); // every function that uses 'this' as the current object should be in here
this.collection = new List();
this.collection.bind('add', this.appendItem); // collection event binder
this.counter = 0;
this.render();
},
render: function(){
var self = this;
$(this.el).append("<button id='add'>Add list item</button>");
$(this.el).append("<button id='save'>SAVE</button>");
$(this.el).append("<ul></ul>");
_(this.collection.models).each(function(item){ // in case collection is not empty
self.appendItem(item);
}, this);
},
addItem: function(){
this.counter++;
var item = new Item();
item.set({
part2: item.get('part2') + this.counter // modify item defaults
});
this.collection.add(item);
},
appendItem: function(item){
var itemView = new ItemView({
model: item
});
$('ul', this.el).append(itemView.render().el);
},
saveCollection: function(){
var collectionLength = this.collection.length;
if(collectionLength > 0){
this.collection.validateModels();
//console.log(status);
}
else
alert('Collection is empty. Please add something.');
}
});
需要注意的关键事项:
- 不要使用
,而是使用$(this.el)
this.$el
- 使用
而不是listenTo
(bind)上的
,以避免内存泄漏(另一个优点是,在您的情况下,
视图将以侦听器作为上下文触发回调)
- 不要覆盖
Backbone的
方法。除非您知道自己在做什么,并且自己处理它所做的所有事情,否则请查看remove
//Model
var Item = Backbone.Model.extend({
defaults: {
part1: 'hello',
part2: 'world'
},
validate: function (attr, options) {
var error = '';
//console.log(attr);
if(attr.part2 == "world1"){
this.trigger('err:world1');
error = 'world 1 error';
}
if(attr.part2 == "world3"){
this.trigger('err:world3');
error = 'world 3 error';
}
}
});
//Collection
var List = Backbone.Collection.extend({
model: Item,
validateModels: function() {
var cloneCollection = this.clone();
var errorModels = this.filter(function(m) {
if (!m.isValid()) {
return m;
}
});
// cloneCollection.remove(errorModels);
return cloneCollection;
}
});
- 使用主干事件散列绑定的事件处理程序的默认上下文是视图本身,以及使用
,无需使用listenTo
\uu.bindAll
- 主干集合有,您可以执行
而不是this.collection.each
(this.collection.models)。each
- 您可以使用下划线,使用它的方法而不是手动生成模板
- 您可以快速执行,而不是
,this.$el.find(selector)
等$(selector,this.el)
- 无需手动创建模型实例,如
,设置其属性,然后将其添加到集合,只需将属性传递到集合newitem()
方法,它将在内部创建一个模型实例add
- 您可以使用集合长度,而不是手动跟踪count属性
//Model
var Item = Backbone.Model.extend({
defaults: {
part1: 'hello',
part2: 'world'
},
validate: function (attr, options) {
var error = '';
//console.log(attr);
if(attr.part2 == "world1"){
this.trigger('err:world1');
error = 'world 1 error';
}
if(attr.part2 == "world3"){
this.trigger('err:world3');
error = 'world 3 error';
}
}
});
//Collection
var List = Backbone.Collection.extend({
model: Item,
validateModels: function() {
var cloneCollection = this.clone();
var errorModels = this.filter(function(m) {
if (!m.isValid()) {
return m;
}
});
// cloneCollection.remove(errorModels);
return cloneCollection;
}
});
- 不要使用内联样式
- 让项目视图呈现自身,并使用
而不是view.el
(我真的不知道是谁发明了这种方法,也不知道为什么)view.render().el
您可以概括代码,如下所示:
var Item=Backbone.Model.extend({
默认值:{
信息:“你好,世界”,
计数:0
},
验证:功能(属性、选项){
如果(属性计数%2!=0){
this.trigger('err',this.get('message')+attr.count+'error');
}
}
});
var List=Backbone.Collection.extend({
型号:项目,
validateModels:function(){
此。每个功能(m){
m、 isValid();//调用模型验证方法
});
}
});
var ItemView=Backbone.View.extend({
标记名:“li”,
模板:35;.template($('#item').text()),
活动:{
'单击span.swap':'swap',
'单击span.delete':'删除'//触发视图的内置删除方法
},
初始化:函数(){
this.listenTo(this.model,'change',this.render);
this.listenTo(this.model'err',this.errorHandler);
这个。render();
},
render:function(){
this.el.html(this.template(this.model.toJSON());
归还这个;
},
交换:函数(){
var words=this.model.get('message').split('');
这个。模型。集合({
消息:words.reverse().join(“”)
});
},
errorHandler:函数(msg){
此.$('span.error').text(msg)
}
});
var ListView=Backbone.View.extend({
模板:$(“#项目视图”).text(),
活动:{
'单击按钮#添加':'添加项',
'单击按钮#保存':'保存集合'
},
初始化:函数(){
this.collection=新列表();
this.listenTo(this.collection,'add',this.appendItem);
这个。render();
},
render:function(){
this.$el.html(this.template);
此.collection.each(函数(模型){
本附录项(型号);
},这个);
},
附加项:函数(){
this.collection.add({
计数:this.collection.length
}, {
验证:正确
});
},
附录项:功能(项){
此.$('ul').append(新项目视图({
型号:项目
})(e.el);
},
saveCollection:函数(){
如果(this.collection.length>0){
this.collection.validateModels();
}否则
警报('集合为空。请添加内容');
}
});
新建ListView().$el.appendTo('body')代码>
li span{
字体系列:无衬线;
}
跨度控制{
光标:指针;
}
互换{
颜色:蓝色;
}
span.delete{
颜色:橙色;
}
广度误差{
颜色:红色;
}
[互换]
[删除]
添加列表项
拯救
哇,谢谢@TJ,这很有帮助。我一定会记住你的建议并付诸实施。