操作后对列表视图进行主干排序和更新
Backbone Sorting and Updating a listview after an action
我正在尝试制作我的第一个主干应用程序,但遇到了一个我无法解决的问题。。
我有一个链接列表,每个链接旁边都有一个计数器,当我点击一个链接时,我希望计数器增加1。(我已经做了这个,它正在工作)
接下来,如果计数器值高于上面的链接,我希望我单击的链接在列表中向上移动。
像这样。
- 第一个链接(4)
- 第二个链接(3)
- 第三链路(3)<-如果我点击这个链接,我希望它向上移动到第二个链接之上
我试过使用comparator和sortBy,但每次我尝试一些东西时,我似乎都无法重新渲染视图,也无法使链接向上移动一个位置。
当主视图初始化时,我最初确实设法对列表进行了排序。但是在我点击其中一个链接后更新视图和列表位置,我不知道如何完成。
我的代码:
(function() {
window.App = {
Models: {},
Collections: {},
Views: {}
};
window.template = function(id) {
return _.template( $('#' + id).html() );
};
//Modellen
App.Models.Task = Backbone.Model.extend({
defaults: {
name: 'Foo Bar Baz',
uri: 'http://www.google.com',
counter: 0
},
validate: function(attr) {
if ( ! $.trim(attr.name) ) {
return 'En opgave kræver en title.';
};
}
});
//Collection
App.Collections.Tasks = Backbone.Collection.extend({
model: App.Models.Task,
comparator: function(task) {
return task.get('counter');
},
});
//Singel view
App.Views.TaskView = Backbone.View.extend({
tagName: 'li',
template: template('Tasks'),
initialize: function() {
this.model.on('change', this.render, this);
this.model.on('destroy', this.remove, this);
},
events: {
'click .edit' : 'retTask',
'click .delete' : 'destroy',
'click .uriLink' : 'addCounter'
},
retTask: function() {
var newTaskNavn = prompt('Hvad skal det nye navn være', this.model.get('name'));
if ( !newTaskNavn ) return;
this.model.set('name', newTaskNavn);
},
destroy: function() {
this.model.destroy();
},
addCounter: function(e) {
e.preventDefault();
var newCounter = this.model.get('counter');
this.model.set('counter', newCounter + 1);
},
remove: function() {
this.$el.remove();
},
render: function() {
this.$el.html(this.template(this.model.toJSON()) );
return this;
}
});
//Collection View
App.Views.TasksView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.collection.on('add', this.addOne, this);
this.render();
},
render: function() {
this.collection.each(this.addOne, this);
return this;
},
addOne: function(task) {
var taskView = new App.Views.TaskView({ model: task });
this.$el.append(taskView.render().el);
}
});
App.Views.AddTask = Backbone.View.extend({
el: '#addTask',
initialize: function() {
},
events: {
'submit' : 'submit'
},
submit: function(e) {
e.preventDefault();
var taskNavn = $(e.currentTarget).find('.navnClass').val(),
uriNum = $(e.currentTarget).find('.uriClass').val();
if ( ! $.trim(taskNavn)) {
var test = prompt('opgaven skal have et navn', '');
if ( ! $.trim(test)) return false;
taskNavn = test;
}
if( uriNum.indexOf( "http://" ) == -1 ) {
addedValue = 'http://',
uriNum = addedValue + uriNum;
}
$(e.currentTarget).find('input[type=text]').val('').focus();
//var task = new App.Models.Task({ name: taskNavn, uri: uriNum });
this.collection.add({ name: taskNavn, uri: uriNum });
}
});
// new tasks collection
var tasks = new App.Collections.Tasks([
{
name: 'Foo',
uri: 'www.google.com',
counter: 3
},
{
name: 'Bar',
uri: 'http://google.com',
counter: 2
},
{
name: 'Baz',
uri: 'http://www.google.com',
counter: 1
}
]);
// tasks.comparator = function(task) {
// return task.get("counter");
// };
tasks.sort();
// new collection view (add)
var addTaskView = new App.Views.AddTask({ collection: tasks});
// new collection view
var tasksView = new App.Views.TasksView({ collection: tasks });
$('.tasks').html(tasksView.el);
})();
我的HTML:(如果有人想复制场景:)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>LinkList</title>
</head>
<body>
<h1>Mine opgaver</h1>
<form action="" id="addTask">
<input class="navnClass" type="text" placeholder="Link name"><input clas s="uriClass" type="text" placeholder="www.url-here.com">
<button class="nyOpgave">Ny opgave</button><br />
</form>
<div class="tasks">
<script type="text/template" id="Tasks">
<span class="linkNavn"><%= name %></span> - <a href="<%= uri %>" class="uriLink" target="_blank"><%= uri %></a> : [<span class="counterClass"><%= counter %></span>] <button class="edit">Edit</button> <button class="delete">Delete</button>
</script>
</div>
<script src="js/underscore.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script src="js/jquery.js"></script>
<script src="js/backbone.js"></script>
<script src="main.js"></script>
</body>
</html>
有人能帮我算出这个吗?
/干杯Marcel
好的,我已经为您创建了应用程序,正如您希望它运行的那样。我将尝试向您解释整个代码,我写了什么以及为什么要写。
首先,看看JSfiddle:这里是
接下来,让我解释一下:
1.这是我的模型,它存储链接的名称、href、id(在我的示例中没有使用,但为每个模型分配一个唯一的id是一种很好的做法),最后存储链接(模型)的点击次数。
var myModel = Backbone.Model.extend({
defaults:{
'id' : 0,
'name' : null,
'link' : '#',
'clicks' : 0
}
});
2.这个集合存储了我所有的模型,我添加了一个比较器函数,这样当你向集合添加模型时,它就会对集合进行排序。
注意:我添加了一个-
符号,以按点击量降序对集合进行排序(点击量最大的链接将首先出现)
var myCollection = Backbone.Collection.extend({
model: myModel,
comparator: function(item) {
return -item.get('clicks');
}
});
3.现在这是我的主要观点,什么是主要观点?此视图对要显示的列表进行主要渲染。这里的代码非常不言自明。有一件事,this.coll.bind('add change',this.render,this)
,我添加了一个"更改",因为每当这个集合中的任何模型发生更改时,我们都想重新渲染整个列表,当我更改任何链接的计数时,单击它,我就想重新渲染完整列表。
var myView = Backbone.View.extend({
el: $("#someElement"),
tagName : 'ul',
initialize: function() {
this.coll = new myCollection();
this.coll.bind('add change',this.render,this);
},
events: {
"click #add": "add"
},
add: function(e){
e.preventDefault();
var mod = new myModel();
var name = $('#name').val();
var link = $('#link').val();
mod.set({'id':mod.cid, 'name':name,'link':link});
this.coll.add(mod);
},
render : function(){
$('#list').empty();
this.coll.sort();
this.coll.forEach(function(model){
var listItem = new printView({ model: model});
$('#list').append(listItem.render().el);
});
}
});
4.这是我的子观点,为什么我会提出第二个观点,为什么一个观点不够?好吧,考虑一个场景,每个链接都有一个删除按钮(例如),当我点击删除按钮时(我只有一个视图),我如何识别要销毁的模型(从集合中删除?),一种可能的方法是将cid
与每个模型相关联,然后点击我可以执行this.coll.getByCid(),但这不是一个很好的方法,IMHO,所以我为每个模型创建了一个单独的视图。此视图渲染每个模型,不再返回任何内容。
var printView = Backbone.View.extend({
tagName: 'li',
initialize : function(options) {
_.bindAll(this, "render");
},
events:{
"click a": "count"
},
render:function(){
var linkName = this.model.get("name");
var link= this.model.get("link");
var clicks = this.model.get("clicks");
this.$el.append("<a class='link' href='"+link+"'>"+linkName+"</a> ("+clicks+")");
return this;
},
count:function(e){
e.preventDefault();
e.stopPropagation();
var clicks = this.model.get("clicks");
clicks++;
this.model.set({'clicks':clicks});
}
});
5.初始化我的(主)myView
new myView();
注意:我相信这个应用程序/代码可以用更好的方式编写,有一些改进,但以我的能力和它的工作原理(:p),我认为它可以帮助你。
只有在向集合中添加新模型时才会执行集合比较器:当属性发生变化时,它不会更新集合顺序。为了实现这一点,您需要调用collection.sort()
:
App.Collections.Tasks = Backbone.Collection.extend({
model: App.Models.Task,
initialize: function() {
this.on('change:counter', this.sort);
},
comparator: function(task) {
return task.get('counter');
}
});
在列表视图中,您可以监听集合的sort
事件,并重新呈现视图:
App.Views.TasksView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.collection.on('add', this.addOne, this);
this.collection.on('sort', this.render, this);
this.render();
},
render: function() {
//if there are existing child views, remove them
if(this.taskViews) {
_.each(this.taskViews, function(view) {
view.remove();
});
}
this.taskViews = [];
this.collection.each(this.addOne, this);
return this;
},
addOne: function(task) {
var taskView = new App.Views.TaskView({ model: task });
this.$el.append(taskView.render().el);
//keep track of child views
this.taskViews.push(taskView);
}
});
- 如何在动态表更新后刷新整个表排序缓存
- 可拖动和可排序项目编号在更改时更新
- 更新标签数组时如何对其进行排序
- 更新“项目”选项以进行排序
- 使用一次更新对有序列表中的元素重新排序
- MongoDB使用排序和切片更新嵌套数组,不会对代码进行排序
- jQuery - 排序后更新可排序列表
- React Native ListView 不会在排序或检索新数据后更新
- 从服务器更新的 meteor 集合,不会在客户端上被动排序
- D3 - 为什么此排序函数不更新其选择中的所有元素
- 使用 AJAX 回调更新挖空可观察数组会生成随机排序的结果
- knockoutjs ObservableArrays 和排序函数:UI 未更新
- 如何在主干中对列表进行排序时更新模型的顺序属性
- jQuery UI's未激发可排序更新事件
- 使用Redis更新排序集
- 根据数字排序顺序更新自动重新排列HTML列表
- 在backbone.js中,如何使用新的模型数据更新视图,同时在没有完整渲染的情况下保持排序顺序
- 如何区分在同一列表中拖动和从一个列表移动到连接列表时的可排序更新事件
- jQuery可排序更新的数据没有被序列化
- 表排序器不能正确排序更新的行