Backbone.js - 此按钮和事件绑定正确吗?

发布于 2024-12-21 07:14:11 字数 2638 浏览 0 评论 0原文

我正在尝试使用 Backbone.js,创建一个表视图和一个单独的行视图,并尝试将行添加到表中:

“在此处输入图像描述”

我有:

  • 联系人模型
  • 联系人集合
  • 联系人视图(充当 主视图)
  • ContactRow 视图

到目前为止,该项目运行良好 - 除了一个应该触发添加行的功能的按钮。

到目前为止,这是我的代码:

$(function($) {

    window.Contact = Backbone.Model.extend({
        defaults: {
            first_name: "John",
            last_name: "Smith",
            address: "123 Main St"
        }
    }); 


    window.Contacts = Backbone.Collection.extend({
        model: Contact
    }); 



    window.ContactRow = Backbone.View.extend({
        //el: $("#contacts-table table tbody"),     

        row_template: _.template($("#contact-row").html()),

        initialize: function() {
            _.bindAll(this, "render")
        },

        render: function() {
            $("tbody").html("<tr><td>Look at me, I'm a row!</td></tr>");
            return this;
        }
    }); 


    window.ContactsView = Backbone.View.extend({        
        el: $("#contacts-container"),   

        events: {
            "click button#add_contact": "addContact"
        },

        template: _.template($("#contacts-table").html()),

        initialize: function() {
            _.bindAll(this, "render", "addContact", "appendContact");   

            this.collection = new Contacts();
            this.collection.bind("add", this.appendContact);

            var contactRow = new ContactRow();          
            this.render();
            this.appendContact(); // Just a test to see if the function is working
        },

        render: function() {
            $("#button-container").append("<button id='add_contact'>Add Contact</button>");
            $(this.el).html(this.template);
            _(this.collection.models).each(function(contact) {
                appendContact(contact);
            }, this)            
        },

        addContact: function() {
            console.log("yup, it works!"); // well, not yet
            var contact = new Contact();
            this.collection.add(contact);               

        },

        appendContact: function(contact) {
            var contactRow = new ContactRow({
                model: contact
            });

            $("body").append(contactRow.render().el);
        }

    });

     var contactsView = new ContactsView(); 

}, jQuery);

如您所见,我有一个 addContact 函数,该函数与附加到主页上 div 元素的“添加联系人”按钮的单击事件相关联在渲染过程中。

我正在尝试将日志消息写入控制台,但按钮似乎没有触发该方法,我不明白为什么。

今天结束了,我的大脑很疲惫,所以我很感激任何关于这方面的指示。谢谢。

I'm experimenting with Backbone.js by creating a table view, and a seperate row view and trying to add the row to the table:

enter image description here

I have:

  • A Contact model
  • A Contacts collection
  • A Contacts view (acts as the
    main view)
  • A ContactRow view

So far, the project is working fine - except for a button that is supposed to trigger the function that adds the row.

Here is my code so far:

$(function($) {

    window.Contact = Backbone.Model.extend({
        defaults: {
            first_name: "John",
            last_name: "Smith",
            address: "123 Main St"
        }
    }); 


    window.Contacts = Backbone.Collection.extend({
        model: Contact
    }); 



    window.ContactRow = Backbone.View.extend({
        //el: $("#contacts-table table tbody"),     

        row_template: _.template($("#contact-row").html()),

        initialize: function() {
            _.bindAll(this, "render")
        },

        render: function() {
            $("tbody").html("<tr><td>Look at me, I'm a row!</td></tr>");
            return this;
        }
    }); 


    window.ContactsView = Backbone.View.extend({        
        el: $("#contacts-container"),   

        events: {
            "click button#add_contact": "addContact"
        },

        template: _.template($("#contacts-table").html()),

        initialize: function() {
            _.bindAll(this, "render", "addContact", "appendContact");   

            this.collection = new Contacts();
            this.collection.bind("add", this.appendContact);

            var contactRow = new ContactRow();          
            this.render();
            this.appendContact(); // Just a test to see if the function is working
        },

        render: function() {
            $("#button-container").append("<button id='add_contact'>Add Contact</button>");
            $(this.el).html(this.template);
            _(this.collection.models).each(function(contact) {
                appendContact(contact);
            }, this)            
        },

        addContact: function() {
            console.log("yup, it works!"); // well, not yet
            var contact = new Contact();
            this.collection.add(contact);               

        },

        appendContact: function(contact) {
            var contactRow = new ContactRow({
                model: contact
            });

            $("body").append(contactRow.render().el);
        }

    });

     var contactsView = new ContactsView(); 

}, jQuery);

As you can see, I have an addContact function that is tied to the click event of the "Add Contact" button that is being appended to a div element on the main page during the render process.

I'm attempting to write log messages to the console, but the button doesn't seem to be firing off the method and I can't figure out why.

It's the end of the day and my brain is fried so I'd appreciate any pointers on this. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

怪我闹别瞎闹 2024-12-28 07:14:11

这是一个工作示例。我用使用 Backbone 的最佳实践更新了代码。

请注意,我没有通过 Backbone 视图添加按钮。该按钮是html正文的一部分,我只是订阅它的点击事件,然后将联系人添加到联系人集合中。

<html>
  <head>
    <script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'></script>
    <script type='text/javascript' src='http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js'></script>
    <script type='text/javascript' src='http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.5.3/backbone-min.js'></script>
    <script type='text/javascript'>
      $(function() {
        //initialize the contacts collection and add some contacts
        contacts = new Contacts();
        contacts.add(new Contact());
        contacts.add(new Contact());

        //only need to render the ContactsView once
        var view = new ContactsView({ collection: contacts });
        $("body").append(view.render().el);

        //adding a contact to the contacts list when the
        //button is clicked
        $("#add-contact").click(function() {
          contacts.add(new Contact());
        });
      });

      Contact = Backbone.Model.extend({
        defaults: {
          first_name: "John",
          last_name: "Smith",
          address: "123 Main St"
        }
      }); 

      Contacts = Backbone.Collection.extend({
        model: Contact
      }); 

      ContactRow = Backbone.View.extend({
        initialize: function() {
          _.bindAll(this, "render");
          this.template = _.template($("#contact-row").html());
        },

        //every backbone view has a tagName. the default tagName is 'div'
        //we're changing it to a table row
        tagName: 'tr',

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

      ContactsView = Backbone.View.extend({        
        initialize: function() {
          _.bindAll(this, "render");
          this.headerTemplate = $("#contacts-table-header").html();
          this.collection.bind("add", this.renderContact, this);
        },

        //the ContactsView element will be a table
        tagName: 'table',

        render: function() {
          $(this.el).html(this.headerTemplate);

          this.collection.each(function(contact) {
            this.renderContact(contact);
          }, this);

          return this;
        },

        renderContact: function(contact) {
          var contactView = new ContactRow({ model: contact });
          $(this.el).append(contactView.render().el);
        }
      });

    </script>

    <script type='text/template' id='contact-row'>
      <td><%= first_name %></td>
      <td><%= last_name %></td>
      <td><%= address %></td>
    </script>

    <script type='text/template' id='contacts-table-header'>
      <thead>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Address</th>
      </thead>
    </script>
  </head>
  <body>
    <button id="add-contact">Add Contact</button>
  </body>
</html>

Here's a working example. I updated the code with best practices for using Backbone.

Notice I didn't add the button through a Backbone view. The button is part of the html body, and I just subscribe to its click event and then add a contact to the contacts collection.

<html>
  <head>
    <script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'></script>
    <script type='text/javascript' src='http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js'></script>
    <script type='text/javascript' src='http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.5.3/backbone-min.js'></script>
    <script type='text/javascript'>
      $(function() {
        //initialize the contacts collection and add some contacts
        contacts = new Contacts();
        contacts.add(new Contact());
        contacts.add(new Contact());

        //only need to render the ContactsView once
        var view = new ContactsView({ collection: contacts });
        $("body").append(view.render().el);

        //adding a contact to the contacts list when the
        //button is clicked
        $("#add-contact").click(function() {
          contacts.add(new Contact());
        });
      });

      Contact = Backbone.Model.extend({
        defaults: {
          first_name: "John",
          last_name: "Smith",
          address: "123 Main St"
        }
      }); 

      Contacts = Backbone.Collection.extend({
        model: Contact
      }); 

      ContactRow = Backbone.View.extend({
        initialize: function() {
          _.bindAll(this, "render");
          this.template = _.template($("#contact-row").html());
        },

        //every backbone view has a tagName. the default tagName is 'div'
        //we're changing it to a table row
        tagName: 'tr',

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

      ContactsView = Backbone.View.extend({        
        initialize: function() {
          _.bindAll(this, "render");
          this.headerTemplate = $("#contacts-table-header").html();
          this.collection.bind("add", this.renderContact, this);
        },

        //the ContactsView element will be a table
        tagName: 'table',

        render: function() {
          $(this.el).html(this.headerTemplate);

          this.collection.each(function(contact) {
            this.renderContact(contact);
          }, this);

          return this;
        },

        renderContact: function(contact) {
          var contactView = new ContactRow({ model: contact });
          $(this.el).append(contactView.render().el);
        }
      });

    </script>

    <script type='text/template' id='contact-row'>
      <td><%= first_name %></td>
      <td><%= last_name %></td>
      <td><%= address %></td>
    </script>

    <script type='text/template' id='contacts-table-header'>
      <thead>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Address</th>
      </thead>
    </script>
  </head>
  <body>
    <button id="add-contact">Add Contact</button>
  </body>
</html>
喵星人汪星人 2024-12-28 07:14:11

这是因为您在主干遍历您的事件集合之后追加

当您创建主干视图 delegateEvents 时,会在幕后调用。这是主干查看事件哈希并将所有内容连接起来的地方。要修复以下任一问题:

  • 在创建视图之前附加

  • 或在渲染后手动调用主干的 delegateEvents

所以你的渲染函数可能看起来像:

render: function() {
    $("#button-container").append("<button id='add_contact'>Add Contact</button>");
    $(this.el).html(this.template);
    this.delegateEvents(); // re-wire events matching selectors in the event hash
    _(this.collection.models).each(function(contact) {
        appendContact(contact);
    }, this)
    return this; // you should also do this so you can chain         
},

更新:

你必须手动调用delegateEvents这似乎很奇怪。也可能是 #button-contianer 不是视图的 el 的子级。该事件哈希中的所有选择器的范围都为 el,因此,如果 #button-contianer 不是它的子级,则 button#add_contact > 选择器永远不会找到任何东西。作为概念证明,请尝试以下操作:在渲染方法中:

render: function() {
  console.log($(this.el).find("button#add_contact").length) // get anything?
  ...

This is because you're appending<button id='contact'> after backbone has traversed your event collection.

When you create a backbone view delegateEvents is called behind the scenes. This is where backbone looks at your events hash and wires everything up. To fix Either:

  • append <button id='contact'> before creating the view

    or

  • or manually call backbone's delegateEvents after rendering

So your render function may look like:

render: function() {
    $("#button-container").append("<button id='add_contact'>Add Contact</button>");
    $(this.el).html(this.template);
    this.delegateEvents(); // re-wire events matching selectors in the event hash
    _(this.collection.models).each(function(contact) {
        appendContact(contact);
    }, this)
    return this; // you should also do this so you can chain         
},

Update:

It seems odd that you'd have to manually call delegateEvents. It could also be that #button-contianer isn't a child of the view's el. All of the selectors in that event hash are scoped to el, so if #button-contianer isn't a child of it the button#add_contact selector will never find anything. As a proof of concept, try this: in your render method:

render: function() {
  console.log($(this.el).find("button#add_contact").length) // get anything?
  ...
兔小萌 2024-12-28 07:14:11
        _(this.collection.models).each(function(contact) {
            appendContact(contact);
        }, this) 

此代码不起作用,因为您没有名为 appendContact 的变量。应该是:

        _(this.collection.models).each(this.appendContact(contact), this);
        _(this.collection.models).each(function(contact) {
            appendContact(contact);
        }, this) 

This code won't work, because you don't have a variable named appendContact. Should be:

        _(this.collection.models).each(this.appendContact(contact), this);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文