I'm trying to build a todo list with multiple lists. Everything works perfectly fine. The issue es when I want to use JQuery UI Sortable. I'm adding the snippet in my TaskListView in the render function, but I had to wrap it into a setTimeout function so that it waits until the DOM is loaded.
I'm pretty sure there is a better way to do this, but I just couldn't find it yet. Help is appreciated.
var TaskView = Backbone.View.extend({
initialize: function(task) {
this.task = task;
},
render: function() {
var pletedClass = "pletedTask";
if (this.taskpleted == 100) pletedClass = "pendingTask";
var html = ""
+ "<li class='task-<%= task.get('id') %> ' data-id='<%= task.get('id') %>' sortable='true'>"
+ "<div class='float-left'><i class='icon-trash removeTask' data-id='<%= task.get('id') %>'></i></div>"
+ "<div class='float-left'>"
+ "<span class='editTask ' data-type='title' data-id='<%= task.get('id') %>'><%= task.get('title') %></span> "
+ "</div>"
+ "<div class='float-right'>"
+ "<span class='editTask task-responsible label' data-type='responsible' data-id='<%= task.get('id') %>'><%= task.get('responsible') %></span>"
+ "<span class='editTask task-deadline label' data-type='ended' data-id='<%= task.get('id') %>'><%= task.get('ended') %></span>"
+ "<span class='label criticallyLevelToggle editTask <%= criticallyLevelClass %>' data-type='pleted' data-id='<%= task.get('id') %>'><%= parseInt(task.get('pleted')) %>%</span>"
+ "</div>"
+ "<div class='clear'> </div>"
+"</li>";
var template = _.template( html, {task: this.task, criticallyLevelClass:this.task.getCriticallyLevelClass(), pleted: pletedClass});
this.$el.html(template);
return this;
}
});
var TaskListView = Backbone.View.extend({
initialize: function(tasks) {
this.tasks = tasks;
},
render: function() {
var html = ""
+"<ul class='tasks'>"
+"<%= tasksli %>"
+"<li><div class='float-left'><input type='text' placeholder='New task...' class='new-task' name='new-task'/></div><div class='clear'> </div></li>"
+"</ul>";
+ "";
var tasksRendered = "";
if (_.isArray(this.tasks)) {
for (var i = 0; i < this.tasks.length; i++) {
var tView = new TaskView(new Task(this.tasks[i]));
tasksRendered += tView.render().el.innerHTML;
};
}
var template = _.template(html, { tasksli: tasksRendered});
this.$el.html(template);
setTimeout(function(){this.$('.tasks').sortable({
stop: function(e, ui) {
ui.item.trigger('drop', ui.item.index());
}
});}, 500);
return this;
}
});
I'm trying to build a todo list with multiple lists. Everything works perfectly fine. The issue es when I want to use JQuery UI Sortable. I'm adding the snippet in my TaskListView in the render function, but I had to wrap it into a setTimeout function so that it waits until the DOM is loaded.
I'm pretty sure there is a better way to do this, but I just couldn't find it yet. Help is appreciated.
var TaskView = Backbone.View.extend({
initialize: function(task) {
this.task = task;
},
render: function() {
var pletedClass = "pletedTask";
if (this.task.pleted == 100) pletedClass = "pendingTask";
var html = ""
+ "<li class='task-<%= task.get('id') %> ' data-id='<%= task.get('id') %>' sortable='true'>"
+ "<div class='float-left'><i class='icon-trash removeTask' data-id='<%= task.get('id') %>'></i></div>"
+ "<div class='float-left'>"
+ "<span class='editTask ' data-type='title' data-id='<%= task.get('id') %>'><%= task.get('title') %></span> "
+ "</div>"
+ "<div class='float-right'>"
+ "<span class='editTask task-responsible label' data-type='responsible' data-id='<%= task.get('id') %>'><%= task.get('responsible') %></span>"
+ "<span class='editTask task-deadline label' data-type='ended' data-id='<%= task.get('id') %>'><%= task.get('ended') %></span>"
+ "<span class='label criticallyLevelToggle editTask <%= criticallyLevelClass %>' data-type='pleted' data-id='<%= task.get('id') %>'><%= parseInt(task.get('pleted')) %>%</span>"
+ "</div>"
+ "<div class='clear'> </div>"
+"</li>";
var template = _.template( html, {task: this.task, criticallyLevelClass:this.task.getCriticallyLevelClass(), pleted: pletedClass});
this.$el.html(template);
return this;
}
});
var TaskListView = Backbone.View.extend({
initialize: function(tasks) {
this.tasks = tasks;
},
render: function() {
var html = ""
+"<ul class='tasks'>"
+"<%= tasksli %>"
+"<li><div class='float-left'><input type='text' placeholder='New task...' class='new-task' name='new-task'/></div><div class='clear'> </div></li>"
+"</ul>";
+ "";
var tasksRendered = "";
if (_.isArray(this.tasks)) {
for (var i = 0; i < this.tasks.length; i++) {
var tView = new TaskView(new Task(this.tasks[i]));
tasksRendered += tView.render().el.innerHTML;
};
}
var template = _.template(html, { tasksli: tasksRendered});
this.$el.html(template);
setTimeout(function(){this.$('.tasks').sortable({
stop: function(e, ui) {
ui.item.trigger('drop', ui.item.index());
}
});}, 500);
return this;
}
});
Share
Improve this question
asked Jun 13, 2013 at 12:55
rapslirapsli
7991 gold badge11 silver badges25 bronze badges
3
-
you might want to use
$(document).ready(function() { //your code here });
to solve that problem – scones Commented Jun 13, 2013 at 12:58 - 2 Unrelated hint: Instead of concatenating your HTML inside your JS you can add this to your HTML: <script type="text/template" id="my-template"> [insert html code] </script>. In your javascript use: template:_.template($('#my-template').html()) – Anonymoose Commented Jun 13, 2013 at 13:01
- Hazaart: Thanks... I will take a look at that. Would make everything a bit more readable ;) – rapsli Commented Jun 13, 2013 at 13:09
1 Answer
Reset to default 5Instead of setTimeout
, just use $(function () { })
(or $(document).ready
) as you would normally to wait for the DOM to be ready. There is nothing special about these functions, and you can add new callbacks to them at any point. All you have to worry about is maintaining the meaning of this
in your callback.
render: function() {
var html = ""
+"<ul class='tasks'>"
+"<%= tasksli %>"
+"<li><div class='float-left'><input type='text' placeholder='New task...' class='new-task' name='new-task'/></div><div class='clear'> </div></li>"
+"</ul>";
+ "";
var tasksRendered = "";
if (_.isArray(this.tasks)) {
for (var i = 0; i < this.tasks.length; i++) {
var tView = new TaskView(new Task(this.tasks[i]));
tasksRendered += tView.render().el.innerHTML;
};
}
var template = _.template(html, { tasksli: tasksRendered});
this.$el.html(template);
var self = this;
$(function(){
self.$('.tasks').sortable({
stop: function(e, ui) {
ui.item.trigger('drop', ui.item.index());
}
})
return this;
}
Alternatively, (and probably more correctly) take steps to make sure that your backbone view isn't having its render
method called until the DOM is ready.