简体   繁体   English

Backbone.js视图是一个简单的选择列表

[英]A Backbone.js view that is a simple select list

I've built a Backbone-powered library that allows a user to add/remove items, much like the Todos example. 我已经构建了一个支持Backbone的库,允许用户添加/删除项目,就像Todos示例一样。

Every time an item is add or removed - or the entire collection is refreshed - I need two other select elements that are on other areas of the page to re-populate with the latest items as options. 每次添加或删除项目时 - 或者刷新整个集合 - 我需要在页面的其他区域上另外选择两个选项元素,以便将最新项目作为选项重新填充。 How would this be implemented, do I simply re-populate the select element in the render function of the view which holds a reference to the collection? 如何实现,我只是重新填充视图的render函数中的select元素,该元素包含对集合的引用?

I'm tempted to create a view just for the select options but this seems like overkill, especially when considering the view doesn't need to re-act to any events. 我很想为选择选项创建一个视图,但这似乎有些过分,特别是在考虑视图不需要重新处理任何事件时。 The select options are used by other views to populate form data. 其他视图使用选择选项来填充表单数据。

You're correct: create a unique view for each select option. 你是对的:为每个选择选项创建一个唯一的视图。 It's not overkill at all; 它根本不是矫枉过正; that's what Views are for. 这就是视图的用途。 They listen for events from their models, in this case the item list, and redraw themselves upon receiving an event. 他们从模型中侦听事件,在这种情况下是项目列表,并在收到事件时重绘自己。 They have container designations, so once you've established those in the parameters for the View subclass, you never need to think about them again. 它们有容器名称,所以一旦你在View子类的参数中建立了它们,你就再也不需要考虑它们了。 You can style them independently. 你可以独立设计它们。

That's the whole point of the Views being the way they are. 这就是观点的全部观点

More importantly, you could also abstract out "view of a list of things," and then each of your specific views can inherit from that view, and add two features: the filter ("latest"), and the renderer. 更重要的是,您还可以抽象出“事物列表视图”,然后每个特定视图都可以从该视图继承,并添加两个功能:过滤器(“最新”)和渲染器。 You have to write the renderer anyway; 无论如何你必须写渲染器; you may as well exploit a little syntatic sugar to make it clear what you're rendering where. 你也可以利用一点点的合成糖来清楚你在哪里渲染。 It's better than writing comments. 这比撰写评论更好。

Not to distract from Elf Sternberg's already excellent answer, but to add a little context: 不要分散Elf Sternberg已经很好的答案,但要添加一些背景:

Don't loop over collections in your templates 不要在模板中循环集合

If you want to do this, you might as well just use HTML partials and AJAX. 如果你想这样做,你也可以只使用HTML部分和AJAX。 Instead, use a Backbone View that renders its own views (the granularity is what minimizes server syncs and page refreshes). 相反,使用呈现其自己的视图的Backbone View(粒度是最小化服务器同步和页面刷新的内容)。 This is recursive, you can repeat this pattern until there is no more associated data to loop over. 这是递归的,您可以重复此模式,直到没有更多关联数据循环。

— Jonathan Otto in A Conceptual Understanding of Backbone.js For The Everyman - 乔纳森奥托在概念性理解Backbone.js为每个人

Of course, there are a few gotchas when you want to render subviews. 当然,当你想渲染子视图时, 有一些问题

I did a code search to try and find some examples of how to do this. 我做了一个代码搜索 ,试图找到一些如何做到这一点的例子。 Turns out that the TodoMVC example is a good model for doing this. 事实证明, TodoMVC示例是一个很好的模型。 From the Strider-CD source (MIT License): 来自Strider-CD源 (MIT许可证):

var UserView = Backbone.View.extend({

    //... is a class. not sure how to put that here
    tagName: "option",

    // Cache the template function for a single item.
    template: _.template($('#user-item-template').html()),

    // The DOM events specific to an item.
    // maybe could put links here? but then user couldn't see on mouse-over

    // The UserView listens for changes to its model, re-rendering. Since there's
    // a one-to-one correspondence between a **User** and a **UserView** in this
    // app, we set a direct reference on the model for convenience.
    initialize: function() {
      _.bindAll(this, 'render');
      this.model.bind('change', this.render);
      this.model.bind('destroy', this.remove);
    },

    // Re-render the contents of the User item.
    render: function() {
      $(this.el).html(this.template(this.model.toJSON()));
      return this;
    },

    // Remove the item, destroy the model.
    clear: function() {
      this.model.clear();
    }

  });

  // The Application
  // ---------------

  // Our overall **AppView** is the top-level piece of UI.
  var UsersView = Backbone.View.extend({
    // Instead of generating a new element, bind to the existing skeleton of
    // the App already present in the HTML.
    el: $("#user-form"),

    // no events here either at this time

    // At initialization we kick things off by
    // loading list of Users from the db
    initialize: function() {
      _.bindAll(this, 'addAll', 'addOne','render');

      Users.bind('add', this.addOne);
      Users.bind('reset', this.addAll);
      Users.bind('all', this.render);

      console.log("fetching Users");
      Users.fetch();
    },

    // Re-rendering the App just means refreshing the statistics -- the rest
    // of the app doesn't change.
    render: function() {
      console.log("rendering User AppView");
      // might want to put some total stats for the Users somewhere on the page

    },

    // Add a single todo item to the list by creating a view for it, and
    // appending its element to the `<ul>`.
    addOne: function(User) {
      console.log("adding one User: " + User.get("id") + "/" + User.get("email"));
      var view = new UserView({model: User});
      this.$("#user-list").append(view.render().el);
    },

    // Add all items in the **Users** collection at once.
    addAll: function() {
      console.log("adding all Users");
      console.log(Users.length + " Users");
      Users.each(this.addOne);
    }


  });
  // Finally, we kick things off by creating the **App**.
  console.log("starting userapp now");
  var UsersApp = new UsersView();

});

Additional examples of a select list view with option sub-views can be found in: 可以在以下位置找到带有选项子视图的选择列表视图的其他示例:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM