最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Backbone.js DOM isn't ready in render method to apply jquery magic - Stack Overflow

programmeradmin2浏览0评论

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'>&nbsp;</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'>&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;
    }
});

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'>&nbsp;</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'>&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;
    }
});
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
Add a ment  | 

1 Answer 1

Reset to default 5

Instead 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'>&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 probably more correctly) take steps to make sure that your backbone view isn't having its render method called until the DOM is ready.

发布评论

评论列表(0)

  1. 暂无评论