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

发布于 2024-11-07 07:40:51 字数 233 浏览 1 评论 0原文

我构建了一个 Backbone 支持的库,允许用户添加/删除项目,就像 Todos 示例一样。

每次添加或删除项目 - 或刷新整个集合 - 我需要页面其他区域上的另外两个选择元素来重新填充最新项目作为选项。这是如何实现的,我是否只需在保存对集合的引用的视图的渲染函数中重新填充选择元素?

我很想仅为选择选项创建一个视图,但这似乎有点过分了,特别是考虑到视图不需要对任何事件做出反应时。其他视图使用选择选项来填充表单数据。

I've built a Backbone-powered library that allows a user to add/remove items, much like the Todos example.

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?

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.

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

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

发布评论

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

评论(2

焚却相思 2024-11-14 07:40:51

您是对的:为每个选择选项创建一个独特的视图。这一点也不过分;这就是视图的用途。他们监听来自模型的事件,在本例中是项目列表,并在收到事件后重新绘制自己。它们具有容器名称,因此一旦您在 View 子类的参数中建立了这些名称,您就再也不需要考虑它们了。您可以独立设计它们。

这就是视图的全部要点

更重要的是,您还可以抽象出“事物列表的视图”,然后每个特定视图都可以从该视图继承,并添加两个功能:过滤器(“最新”)和渲染器。无论如何你都必须编写渲染器;您也可以利用一些语法糖来明确您在何处渲染什么。这比写评论更好。

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. 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.

Bonjour°[大白 2024-11-14 07:40:51

不是为了分散人们对 Elf Sternberg 已经很好的答案的注意力,而是添加一些背景信息:

不要循环模板中的集合

如果你想这样做,你不妨只使用 HTML 部分和
阿贾克斯。相反,使用呈现其自己的视图(
粒度是最大限度地减少服务器同步和页面刷新的因素)。这
是递归的,你可以重复这个模式,直到不再有
要循环的关联数据。

— Jonathan Otto,普通人对 Backbone.js 的概念理解

当然,当您想要渲染子视图时,会遇到一些问题

我进行了代码搜索来尝试找到一些如何执行此操作的示例。事实证明 TodoMVC 示例 是执行此操作的一个很好的模型。来自 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();

});

带有选项子视图的选择列表视图的其他示例可以在以下位置找到:

Not to distract from Elf Sternberg's already excellent answer, but to add a little context:

Don't loop over collections in your templates

If you want to do this, you might as well just use HTML partials and
AJAX. Instead, use a Backbone View that renders its own views (the
granularity is what minimizes server syncs and page refreshes). 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

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. From the Strider-CD source (MIT License):

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:

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