2

私は最初の RequireJS/Backbone アプリに取り組んでいますが、壁にぶつかりました。ここにはコードの匂いがたくさんありますが、パターンを見逃していることはわかっています。

すべてのプロモーションを表示するルートと、特定のプロモーション (ID による) を表示するルートがあります。

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

プロモーション ビューのイニシャライザで、PromotionsCollection を新しく作成してフェッチします。コレクションのリセット イベントもサブスクライブします。これは addAll を呼び出し、最終的にすべてのプロモーションの 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. メソッド内で render を呼び出してaddAll、テンプレートを取り込みます。確かにそのコードを に移動できましたaddAllが、全体的にこのコードも臭いです。テンプレート自体のレンダリングを担当し、必要に応じてリスト/編集ビューをインスタンス化する「親ビュー」が必要ですか?

ありがとう!

4

1 に答える 1

2

これが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;
    }

繰り返しますが、これは 1 つの方法にすぎず、ひどく間違っている可能性がありますが、これが私のやり方であり、うまく機能しているようです。私は通常、サブビューが最終的に代替htmlでレンダリングされるdomに「読み込み中」メッセージを入れます。

于 2012-12-08T00:24:43.287 に答える