主干子视图事件不触发,无法访问this.model [英] Backbone subview event doesn't fire, access to this.model lost

查看:69
本文介绍了主干子视图事件不触发,无法访问this.model的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用带有子视图的主视图和它自己的子视图,并且在子子视图上丢失了事件.

I'm using a master view with a subview with it's own subview, and I am losing the event on the sub-sub view.

在SO中,看起来好像需要一个委托事件,但我不知道如何或在何处.

Looking in SO, it looks like a delegateEvents is needed, but I can't figure out how or where.

此外,必须将tbody: tbodyEl[ "0" ].outerHTML传递给我的模板似乎真的很棘手,但我不知道它是否与事件问题有关.

Also, it seems really hacky to have to pass tbody: tbodyEl[ "0" ].outerHTML to my template, but I don't know if it's related to the event issue.

任何帮助都将不胜感激.

Any help greatly appreciated.

mainView:

return Backbone.View.extend({
    el: "#content",
    initialize: function () {
        this.render();
    },
    render: function () {
        var todosView = new TodosView({
            collection: projectCol
        });
    }
});

todosView:

todosView:

return Backbone.View.extend({
    el: "#content-body",
    template: _.template([
        '<div class="table-responsive">',
        '<table id="todo-table" class="table">',
        '<span class="caption">Top <%= project %> Tasks&nbsp;&nbsp;<a id="<%= project %>" class="projectName">(See All)</span></a>',
        '<thead>',
        '<tr>',
        '<th>Task</th>',
        '<th>Due</th>',
        '</tr>',
        '</thead>',
        '<%= tbody %>',
        '</table>',
        '</div>'
    ].join("")),
    initialize: function () {
        this.render();
    },
    render: function () {
        var projectName = this.collection.models[0].attributes.project;

        var tbodyEl = $("<tbody />");
        this.collection.each(function (item) {
            var todoView = new TodoView({
                model: item
            });
            tbodyEl.append(todoView.el);
        });
        this.$el.append(this.template({
            project: projectName,
            tbody: tbodyEl["0"].outerHTML
        }));
    }
});

todoView:

return Backbone.View.extend({
    tagName: "tr",
    className: "todo-rec",
    template: _.template([
        "<td>",
        "<label id='task' class='edit'><%= task %></label>",
        "<input id='edited-task' class='new-edit' style='display:none;' value='<%= task %>'>",
        "</td>",
        "<td>",
        "<span id='due' class='edit'><%= due %></span>",
        "<input id='edited-due' class='new-edit' style='display:none;' value='<%= due %>'>",
        "</td>",
    ].join("")),
    events: {
        "click .edit": "editFields"
    },
    initialize: function () {
        this.render();
    },
    render: function () {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    editFields: function () {
        console.log("todoView: editFields clicked"); // <-- does not fire
    }
});

10月25日更新:感谢@WinterSoldier,这就是我的最终结果:代码构建元素在插入DOM之前就已经完成,并且todoView.events可以工作,可以完全访问this.model,此外,它看起来更像'Backbone -ish':

25 Oct Updated: Thanks to @WinterSoldier, this is what I ended up with: code build elements complete before inserting into DOM, and todoView.events works, giving full access to this.model, plus, it looks more 'Backbone-ish':

// mainView:
return Backbone.View.extend( {

    el:             "#content",

    initialize:         function(){
                    this.render();
                },

    render:         function(){
                    $( "#content-body" ).empty();

                    var section = new TodosView( { collection: projectCol } ); // should be returning a section div
                    $( "#content-body" ).append( section.el );
                }                           
} );


// todosView:
return Backbone.View.extend( {

    // used tagName so the element can be built complete before inserting into DOM
    tagName:        "div",
    className:      "table-responsive",

    // tbody changed to empty element
    template:       _.template( [
                    '<table id="todo-table" class="table">',
                        '<span class="caption">Top <%= project %> Tasks&nbsp;&nbsp;<a id="<%= project %>" class="projectName">(See All)</span></a>',
                        '<thead>',
                            '<tr>',
                                '<th>Comp.</th>',
                                '<th>Task</th>',
                                '<th>Due</th>',
                                '<th>Priority</th>',
                                '<th>Delegated To</th>',
                                '<th>Project</th>',
                                '<th>Del.</th>',
                            '</tr>',
                        '</thead>',
                        '<tbody id="tbodyContent"></tbody>',
                    '</table>' ].join( "" )
                ),

    initialize:         function(){
                    this.render();
                },

    render:         function(){
                    // new: render the template first, then append rows in #tbody
                    var projectName = this.collection.models[ 0 ].attributes.project;
                    this.$el.empty().html( this.template( {
                        project: projectName
                    } ) );

                    var this2 = this;
                    this.collection.each( function( item ){
                        var todoView = new TodoView( {model: item} );
                        this2.$el.find( "#tbodyContent" ).append( todoView.el );
                    } );
                    // now returning a <div class="table-responsive" with all rows
                    return this;
                }
    } );



// todoView:
// Note: nothing changed from original code

return Backbone.View.extend( {

    tagName:        "tr",
    className:      "todo-rec",

    template:       _.template( [
                        "<td>",
                            "<label id='task' class='edit'><%= task %></label>",
                            "<input id='edited-task' class='new-edit' style='display:none;' value='<%= task %>'>",
                        "</td>",
                        "<td>",
                            "<span id='due' class='edit'><%= due %></span>",
                            "<input id='edited-due' class='new-edit' style='display:none;' value='<%= due %>'>",
                        "</td>",
                     ].join( "" )
                ),

    events:         {
                    "click .edit":      "editFields"
                },

    initialize:         function() {
                    this.render();
                },

    render:         function() {
                    this.$el.html( this.template( this.model.toJSON() ) );
                    return this;
                },


    editFields:         function() {
                    console.log( "todoView: editFields clicked", this ); 
                }

    } );

推荐答案

让我列出我根据以下问题做出的假设:

let me list out the assumptions I made based on the question:

  • 模板呈现没有问题.
  • 可以将模板代码替换为纯html来检查 事件触发.
  • The template rendering has no issues.
  • The template code may be substituted with plain html to check the event firing.

基于这些假设,我创建了一个具有两个模型的集合,并将它们传递给TodosView,然后从中迭代这些模型以生成行视图,然后将其添加到"tbody"标签中.

Based on those assumption, I created a collection with two models and passed them over to TodosView from which I iterated over those models to generate row view- there by adding it to 'tbody' tag.

请在这里关注小提琴=> https://jsfiddle.net/randomfifaguy/304kffed/1/

Please follow the fiddle here => https://jsfiddle.net/randomfifaguy/304kffed/1/

console.log("hello");
Test = Backbone.Model.extend({});
var testModel1 = new Test({
  'task': 'taskA',
  'due': 'dueByZ'
})
var testModel2 = new Test({
  'task': 'taskB',
  'due': 'dueByY'
})
console.log(testModel1.get('task'));
console.log(testModel2.get('task'));
ModelCollection = Backbone.Collection.extend({});
var models = new ModelCollection([testModel1, testModel2]);
console.log(models);

TodosView = Backbone.View.extend({
    el: "#content-body",
    initialize: function() {
      this.render();
    },
    render: function() {    
    var templ = "<div class='table-responsive'><table id='todo-table'class='table'><span class='caption'>Top Tasks&nbsp;&nbsp;<a id='<%= project %>' class='projectName'>(See All)</span></a><thead><tr><th>Task</th><th>Due</th></tr></thead><tbody></tbody></table></div>";
    $(this.el).html(templ);
    _.each(this.collection.models, function(mdl){
    	var view = new TodoView({
      model: mdl
    });    
    $('tbody').append(view.el);
    });    
  }
});

MainView = Backbone.View.extend({

    el: "#content",

    initialize: function() {
      this.render();
    },

    render: function() {
      new TodosView({
        collection: models
      });
    }
});

TodoView = Backbone.View.extend({
    tagName: "tr",
    className: "todo-rec",
    events: {
      "click .edit": "editFields"
    },
    initialize: function() {
      this.render();
      this.updateContent();
    },
    render: function() {
    var html = "<td><label id='task'class='edit tasklabel'></label><input id='edited-task'class='new-edit taskinput'style='display:none;' value=''></td><td><span id='due' class='edit duelabel'></span><input id='edited-due' class='new-edit dueinput' style='display:none;'value=''></td>"
    this.$el.html(html);
    return this;
    },
    editFields: function() {
      console.log("todoView: editFields clicked");
    },
    updateContent: function() {
      this.$el.find('.tasklabel').text(this.model.get('task'))
      this.$el.find('.taskinput').val(this.model.get('task'))
      this.$el.find('.duelabel').text(this.model.get('due'))
      this.$el.find('.dueinput').val(this.model.get('due'))
    }
});

var mainViewObj = new MainView();

<body>
    <div id='content'>
      Here is a sample div
      <div id="content-body">
        content to be changed
      </div>
    </div>
</body>

但是,我想了解您最外层视图的html,以帮助您更好地工作. 请与小提琴的输出html进行比较,并告诉我. 希望这能回答你的问题.

However I'd like to know your html of the outermost view to help you better. Please compare it with the output html of the fiddle and let me know. Hope that answers your question.

详细回答您的评论 您可能要更改这段代码

Answering your comment in detail You might want to change this piece of code

    //You might want to change this piece of code 

    var tbodyEl = $("<tbody />");
    this.collection.each(function (item) {
        var todoView = new TodoView({
             model: item
        });
        tbodyEl.append(todoView.el);
    });
    this.$el.append(this.template({
            project: projectName,
            tbody: tbodyEl["0"].outerHTML
    }));

您的tbodyEl基本上不会指向任何东西,直到您渲染 在添加到tbody之前,请尝试这样做

Your tbodyEl basically points to nothing until you render try doing this before you append to tbody

    this.$el.append(this.template({
         project: projectName,
         tbody: tbodyEl["0"].outerHTML
    }));
   // followed by

    this.collection.each(function (item) {
         var todoView = new TodoView({
              model: item
          });
          tbodyEl.append(todoView.el);
    });

这篇关于主干子视图事件不触发,无法访问this.model的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆