【问题标题】:Accessing collection in multiple views - Backbone + RequireJS在多个视图中访问集合 - Backbone + RequireJS
【发布时间】:2012-11-23 23:27:14
【问题描述】:

我正在开发我的第一个 RequireJS/Backbone 应用程序,但我碰壁了。这里有很多代码味道,我知道我只是缺少模式。

我有一条显示所有促销的路线,还有一条显示特定促销的路线(按 ID):

showPromotions: function () {
    var promotionsView = new PromotionsView();
},
editPromotion: function (promotionId) {
    vent.trigger('promotion:show', promotionId);
}

在我的促销视图初始化程序中,我新建了我的 PromotionsCollection 并获取。我还订阅了集合上的重置事件。这调用 addAll 最终构建所有 Promotions 的 ul 并将其附加到 DOM 中的容器 div 中。

define([
  'jquery',
  'underscore',
  'backbone',
  'app/vent',
  'models/promotion/PromotionModel',
  'views/promotions/Promotion',
  'collections/promotions/PromotionsCollection',
  'text!templates/promotions/promotionsListTemplate.html',
  'views/promotions/Edit'
], function ($, _, Backbone, vent, PromotionModel, PromotionView, PromotionsCollection, promotionsListTemplate, PromotionEditView) {
    var Promotions = Backbone.View.extend({
        //el: ".main",
        tagName: 'ul',
        initialize: function () {
            this.collection = new PromotionsCollection();
            this.collection.on('reset', this.addAll, this);
            this.collection.fetch();
        },

        render: function () {
            $("#page").html(promotionsListTemplate);
            return this;
        },
        addAll: function () {
            //$("#page").html(promotionsListTemplate);
            this.$el.empty().append('<li class="hide hero-unit NoCampaignsFound"><p>No campaigns found</p></li>');
            this.collection.each(this.addOne, this);
            this.render();
            $("div.promotionsList").append(this.$el);
        },

        addOne: function (promotion) {
            var promotionView = new PromotionView({ model: promotion });
            this.$el.append(promotionView.render().el);
        }    
    });
    return Promotions;
});

列表中的每个促销都有一个编辑按钮,其href 为#promotion/edit/{id}。如果我先导航到列表页面,然后单击编辑,它就可以正常工作。但是,我无法直接导航到编辑页面。我知道这是因为我在视图的初始化方法中填充了我的集合。我可以有一个“if collection.length == 0, fetch”类型的调用,但我更喜欢不需要执行这种检查的设计。我的问题:

  1. 无论我走哪条路线,我如何确保我的收藏被填充?
  2. 我在addAll 方法中调用render 来拉入我的模板。我当然可以将该代码移至addAll,但总体而言,该代码也有异味。我是否应该有一个负责呈现模板本身并根据需要实例化我的列表/编辑视图的“父视图”?

谢谢!

【问题讨论】:

    标签: backbone.js requirejs


    【解决方案1】:

    这里有一个。请记住,有不止一种方法可以做到这一点。事实上,这可能不是最好的,但我自己做,所以也许其他人可以帮助我们俩!

    首先,您在这个 js 文件中有很多导入。如果您像这样导入它们,随着时间的推移添加/删除它们会更容易管理:

    define(function( require ){
      // requirejs - too many includes to pass in the array
      var $ = require('jquery'),
          _ = require('underscore'),
          Backbone = require('backbone'),
          Ns = require('namespace'),
          Auth = require('views/auth/Auth'),
          SideNav = require('views/sidenav/SideNav'),
          CustomerModel = require('models/customer/customer');
          // blah blah blah...});
    

    不过,这只是一个风格建议,您来电。至于收款业务,是这样的:

      Forms.CustomerEdit = Backbone.View.extend({
    
        template: _.template( CustomerEditTemplate ),
    
        initialize: function( config ){
          var view = this;
          view.model.on('change',view.render,view);
        },
    
        deferredRender: function ( ) {
          var view = this;
          // needsRefresh decides if this model needs to be fetched.
          // implement on the model itself when you extend from the backbone
          // base model.
          if ( view.model.needsRefresh() ) {
            view.model.fetch();
          } else {
            view.render();        
          }
        },
    
        render:function () {
          var view = this;
          view.$el.html( view.template({rows:view.model.toJSON()}) );
          return this;
        }
    
      });
    
    
       CustomerEdit = Backbone.View.extend({
    
        tagName: "div",
    
        attributes: {"id":"customerEdit",
                     "data-role":"page"},
    
        template: _.template( CustomerEditTemplate, {} ),
    
    
        initialize: function( config ){
          var view = this;
          // config._id is passed in from the router, as you have done, aka promotionId
          view._id = config._id;
    
          // build basic dom structure
          view.$el.append( view.template );
    
          view._id = config._id;
          // Customer.Foo.Bar would be an initialized collection that this view has
          // access to.  In this case, it might be a global or even a "private" 
          // object that is available in a closure 
          view.model = ( Customer.Foo.Bar ) ? Customer.Foo.Bar.get(view._id) : new CustomerModel({_id:view._id});
    
          view.subViews = {sidenav:new Views.SideNav({parent:view}),
                           auth:new Views.Auth(),
                           editCustomer: new Forms.CustomerEdit({parent:view,
                                          el:view.$('#editCustomer'),
                                          model:view.model})
                                        };
    
        },
    
        render:function () {
          var view = this;
          // render stuff as usual
          view.$('div[data-role="sidetray"]').html( view.subViews.sidenav.render().el );
          view.$('#security').html( view.subViews.auth.render().el );
          // magic here. this subview will return quickly or fetch and return later
          // either way, since you passed it an 'el' during init, it will update the dom
          // independent of this (parent) view render call.
          view.subViews.editCustomer.deferredRender();
    
          return this;
        }
    

    再说一次,这只是一种方法,可能是大错特错,但我就是这样做的,而且看起来效果很好。我通常在 dom 中放置一条“正在加载”消息,子视图最终会用替换 html 呈现。

    【讨论】:

    • 抱歉,本周末在假日派对场地。我会在今天/明天回到应用程序的那个部分时检查一下并看看。
    • 我只是想确认一下——你的 needsRefresh() 方法——这只是一个基于初始获取设置的布尔值吗?还是那里有更复杂的东西?如果更复杂,您可以编辑您的示例以将该方法包含在模型中吗?实际上,为了其他人,我想只是更新您的解决方案以包含带有刷新的模型会有所帮助。
    • 很想知道您对上述问题的看法
    • 当然,没问题。我实际上已经放弃了上面的代码,以使用事件的更解耦的方式。我可以试着为你打包。
    猜你喜欢
    • 2014-02-04
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-22
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    相关资源
    最近更新 更多