Backbone.js DOM not ready in render method to use jquery magic

I am trying to create a todo list with multiple lists. Everything works perfectly. The problem occurs when I want to use jQuery UI Sortable. I am adding a fragment to my TaskListView in the rendering function, but I had to translate it into the setTimeout function so that it waits for the DOM to load.

I am sure there is a better way to do this, but I just could not find it. Help is appreciated.

var TaskView = Backbone.View.extend({ initialize: function(task) { this.task = task; }, render: function() { var completedClass = "completedTask"; if (this.task.completed == 100) completedClass = "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='completed' data-id='<%= task.get('id') %>'><%= parseInt(task.get('completed')) %>%</span>" + "</div>" + "<div class='clear'>&nbsp;</div>" +"</li>"; var template = _.template( html, {task: this.task, criticallyLevelClass:this.task.getCriticallyLevelClass(), completed: completedClass}); 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'>&nbsp;</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; } }); 
+4
source share
1 answer

Instead of setTimeout just use $(function () { }) (or $(document).ready ), since you usually expect the DOM to be ready. There is nothing special about these functions, and you can add new callbacks to them at any time. All you need to worry about is storing the this value 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'>&nbsp;</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 perhaps more correctly), follow the steps to make sure your skeletal view does not have its render method until the DOM is ready.

+5
source

Source: https://habr.com/ru/post/1486013/


All Articles