主干子视图事件没有触发,访问这个.模型丢失

Backbone subview event doesn't fire, access to this.model lost

本文关键字:访问 模型 视图 事件      更新时间:2023-09-26

我使用一个主视图与子视图与它自己的子视图,我失去了子视图上的事件。

在SO中,它看起来像一个delegateEvents是需要的,但我不知道如何或在哪里。

另外,把tbody: tbodyEl[ "0" ].outerHTML传递给我的模板似乎真的很糟糕,但我不知道它是否与事件问题有关。

任何帮助都非常感谢。

mainView:

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

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
    }
});

25 Oct更新:感谢@WinterSoldier,这就是我最终得到的:代码构建元素在插入DOM和todoView之前完成。事件的工作,给予完全访问这个。模特,另外,它看起来更"骨气":

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

让我列出我根据这个问题所做的假设:

  • 模板渲染没有问题
  • 模板代码可以用纯html代替事件发射。

基于这些假设,我创建了一个具有两个模型的集合,并将它们传递给TodosView,从中我迭代这些模型以生成行视图-在那里通过将其添加到'tbody'标记。

请跟着这里的小提琴走=>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进行比较,并让我知道。希望这能回答你的问题。

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

    //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基本上不指向任何东西,直到你渲染在添加

之前尝试执行此操作

    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);
    });