【问题标题】:Render issue in View with subviews in Backbone/Require app使用 Backbone/Require 应用程序中的子视图在视图中呈现问题
【发布时间】:2014-10-22 08:17:37
【问题描述】:

从主视图中,我尝试渲染一些应驻留在主视图页面中的子视图,例如成绩视图及其子视图成绩视图,当单击导航栏图标时,一个可见并填满整个页面。主页有一个导航栏,其中包含一次显示此子视图的链接。主页视图类似于带有导航栏的 Facebook 移动应用程序页面,并且子视图(如提要、好友请求等)填充导航栏下的页面。

我已经实现了其中一个子视图,但无法渲染它。 Homeview 成功渲染。每个子视图在初始化时呈现自己,而成绩集合在初始化时获取自己。

主页:

define([
  'jquery',
  'ratchet',
  'underscore',
  'backbone',

  'text!home/hometemplate.html',

  'grades/gradesview',

  ],
  function($, Ratchet, _, Backbone, HomeTemplate, GradesView){
      var HomeView = Backbone.View.extend({

          el: $('body'),
          initialize: function() {
              //X-construct the subviews in initialize to create them once.
              this.gradesView = new GradesView();

              this.render();
          },
          template: _.template( HomeTemplate ),
          render: function() {
              this.$el.html( this.template() );
              //X-Place the Subview element into DOM.
              this.$('#gradesviewcontainer').html( this.gradesView.el );
          },

        });

        return HomeView;
})

成绩视图:

define([
    'underscore',
    'backbone',

    'grades/gradescollection',
    'grades/gradeview',
    ],
    function(_, Backbone, GradesCollection, GradeView){
        var GradesView = Backbone.View.extend({
            el: $('#gradescontainer'),
            //model: GradeModel,
            initialize: function(){
                this.collection = new GradesCollection;
                this.collection.each(function(item) {
                  console.log(item);
                });

                this.render();
            },
            //template:,

            render: function() {
                this.collection.each( function (item) {
                    this.renderGrade( item );
                }, this );
            },

            renderGrade: function(item) {
                this.gradeView = new GradeView( {model: item} );
                this.$el.append( this.gradeView.el );
            },
        });

        return GradesView;
})

成绩单:

define([
    'underscore',
    'backbone',

    'grades/grademodel',
    ],
    function(_, Backbone, GradeModel) {
        var GradesCollection = Backbone.Collection.extend ({

            model: GradeModel,
            url: '/grade',
            initialize: function() {
                this.fetch();
            },

        });

    return GradesCollection;
});

成绩:

define([
    'underscore',
    'backbone',

    'grades/grademodel',
    'text!grades/gradetemplate.html'
    ],
    function(_, Backbone, GradeModel, GradeTemplate){
        var GradeView = Backbone.View.extend({
            tagName: 'div',
            initialize: function(){
                this.render();
            },
            template: _.template( GradeTemplate ),

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

        return GradeView;
})

这里的另一个问题是导航栏链接每个 html 锚点在 homeview 渲染中不起作用。 在 JS 控制台中,我可以看到从我的服务器响应的资源 json,即预期的对象数组:[{"coursename":"Math","gradenumeric":100},{"coursename":"Phys","gradenumeric":80}]。我在这里缺少什么?

【问题讨论】:

    标签: javascript backbone.js


    【解决方案1】:

    我认为您只需从 GradesView 中删除 el: $('#gradescontainer')。您不应该为子视图设置 el 元素,因为您要将其附加到尚未呈现的父视图中。

    我包含了一个仅由el: $('#gradescontainer') 工作的简化版本。在我的示例中,为了简单起见,我删除了 GradeModel 和 GradeCollection 并仅放置了一些占位符代码。

    此示例应渲染“GRADE TEMPLATE”五次,每个等级模型一次。尝试将el: $('#gradescontainer') 放回GradesView,您将看到“GRADE TEMPLATE”不再呈现。

    您的另一个问题是集合在初始化方法中调用了fetch。这使用 AJAX,因此模型将异步加载。初始化 GradesView 时,您需要将侦听器事件绑定到集合。例如:

    this.collection.on('add', this.renderGrade, this);
    

    示例 1:此示例不使用模型/集合。只是说明需要删除el: $('#gradescontainer')

    var GradeView = Backbone.View.extend({
      tagName: 'div',
      initialize: function(){
        this.render();
      },
      template: "GRADE TEMPLATE",
    
      render: function() {
        this.$el.html(this.template);
        return this;
      },
    });
    
    
    var GradesView = Backbone.View.extend({
      initialize: function(){
        this.render();
      },
      render: function() {
        var self = this;
        for (var i = 0; i < 5; i++) {
            self.renderGrade({id:i});
        }
      },
    
      renderGrade: function(item) {
        this.gradeView = new GradeView({model: item});
        this.$el.append(this.gradeView.el);
      },
    });
    
    var HomeView = Backbone.View.extend({
       el: $('#test'),
       initialize: function() {
         this.gradesView = new GradesView();
         this.render();
       },
       template: '<h1>GRADES</h1><div id="gradesviewcontainer"></div>',
       render: function() {
         this.$el.html( this.template );
         this.$('#gradesviewcontainer').html( this.gradesView.el );
       },
    
     });
    
    var v = new HomeView();

    示例 2:此示例使用模型/集合。模型被手动添加到集合中。为简单起见,不使用 Fetch。这与示例1基本相同。

    var GradeModel = Backbone.Model.extend({
      defaults: {
        letter: 'A'
      }
    });
    
    var GradesCollection = Backbone.Collection.extend ({
      model: GradeModel,
      url: '/grade'
    });
    
    var GradeView = Backbone.View.extend({
      tagName: 'div',
      initialize: function(){
        this.render();
      },
      template: _.template("<li><%= letter %></li>"), 
      render: function() {
        this.$el.html(this.template(this.model.attributes));
        return this;
      },
    });
    
    
    var GradesView = Backbone.View.extend({
      initialize: function(){
        this.collection = new GradesCollection();
        this.collection.add(new GradeModel({letter: 'A'}));
        this.collection.add(new GradeModel({letter: 'B'}));
        this.collection.add(new GradeModel({letter: 'C'}));    
        this.collection.add(new GradeModel({letter: 'D'}));
        this.render();
      },
      render: function() {
        this.collection.each( function (item) {
          this.renderGrade( item );
        }, this )
      },
    
      renderGrade: function(item) {
        this.gradeView = new GradeView({model: item});
        this.$el.append(this.gradeView.el);
      },
    });
    
    var HomeView = Backbone.View.extend({
      el: $('#test'),
      initialize: function() {
        this.gradesView = new GradesView();
        this.render();
      },
      template: '<h1>GRADES</h1><div id="gradesviewcontainer"></div>',
      render: function() {
        this.$el.html( this.template );
        this.$('#gradesviewcontainer').html(this.gradesView.el);
      },
    
    });
    
    var v = new HomeView();
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
    <div id="test"></div>

    【讨论】:

    • 我的问题是我认为需要渲染一个集合。我应该看到集合渲染的真正实现。
    • 我正在尝试一个普通的数组。
    • 是的,再看一遍,您的收藏有问题,因为您在初始化期间调用了fetch。由于 fetch 是异步的,因此您需要添加一个侦听器事件。
    • 你的意思是我应该在成绩视图初始化中放一个听。为了清楚起见,当我在 GradesView 中创建 GradesCollection 时,初始化控件不会等待创建 GradesCollection,而是继续执行下一行,例如 this.render()。因此,在其初始化中的 GradesCollection 的 fetch() 获取集合之前,视图呈现没有它。所以这意味着它是异步的。
    • 是的,这很烦人,因为您需要处理这个服务器端。也许只是让服务器上的所有路由呈现您的索引页面。我认为骨干路由器应该呈现正确的页面。使用路由器已经有一段时间了,所以您可能需要进行一些调整。
    猜你喜欢
    • 2014-12-18
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    相关资源
    最近更新 更多