backbone.js无法渲染视图

backbone.js cannot render a view

本文关键字:视图 js backbone      更新时间:2023-09-26

下面是我的一个模块的代码。这是一种spagetti风格的代码,但我想要完成的只是拥有一个模型、一个集合,并呈现一个将数据从集合连接到视图的视图(使用下划线模板)。我失败得很惨。我遇到的问题是,试图运行对testfeed.render()的最后一个调用告诉我render不是一个函数,但它是明确定义的。我能够从api中获取数据并将其添加到集合中。我在这里做错了什么?

 // Create a new module.
  var Tagfeed = app.module();
  // Default model.
  Tagfeed.Model = Backbone.Model.extend({
    defaults : {
        name : '',
        image : ''
    },
    initialize : function(){
        console.log('tagfeed model is initialized');
        this.on("change", function(){
            console.log("An attribute has been changed");
        });
    }
  });
  var feedCollection = Backbone.Collection.extend({
    model: Tagfeed.Model,
    initialize : function () {
        console.log('feedcollection is initialized');
    },
    fetch: function () {
        var thisCollection = this;
        Api_get('/api/test', function(data){
            $.each(data.data, function(){
                thisCollection.add(this);
            });
            return thisCollection;
        })
    }
  });
  var test = new Tagfeed.Model({name:'test'});
  var newFeedCollection = new feedCollection();
  newFeedCollection.fetch();
  console.log(newFeedCollection.at(0));
  var testfeed = Backbone.View.extend({
    el: $('#main'),
    collection : newFeedCollection,
    render: function( event ){
        var compiled_template = _.template( $("#tag-template").html() );
        this.$el.html( compiled_template(this.model.toJSON()) );
        return this; //recommended as this enables calls to be chained.
    }
  });
  testfeed.render();

编辑*来自@mu的更新代码是简短的建议

  // Create a new module.
  var Tagfeed = app.module();
  // Default model.
  var tagModel = Backbone.Model.extend({
    defaults : {
        name : '',
        image : '',
        pins : 0,
        repins : 0,
        impressions : 0
    },
    initialize : function(){
        console.log('tagfeed model is initialized');
        this.on("change", function(){
            console.log("An attribute has been changed");
        });
    }
  });
  var feedCollection = Backbone.Collection.extend({
    model: tagModel,
    initialize : function () {
        console.log('feedcollection is initialized');
    },
    fetch: function () {
        var thisCollection = this;
        Api_get('/reporting/adlift/pin_details', function(data){
            thisCollection.add(data.data);
            return data.data;
        })
    }
  });
  var test = new tagModel({name:'test'});
  var newFeedCollection = new feedCollection();
  newFeedCollection.fetch();
  console.log(newFeedCollection.at(0));
  var TestFeed = Backbone.View.extend({
    el: $('#main'),
    render: function( event ){
        console.log('here');
        var compiled_template = _.template( $("#tag-template").html(), this.collection.toJSON());
        this.el.html( compiled_template );
        return this; //recommended as this enables calls to be chained.
    },
    initialize: function() {
        console.log('initialize view');
        this.collection.on('reset', this.render, this);
    }
  });
  //Tagfeed.testfeed.prototype.render();
  var testfeed = new TestFeed({ collection: newFeedCollection });
  testfeed.render();

现在,当我运行testfeed.render()时,我没有看到任何错误,也没有在render函数中看到console.log。想法?

您的问题就在这里:

var testfeed = Backbone.View.extend({ /*...*/ });
testfeed.render();

这使您的testfeed成为视图"类",您必须使用new创建一个新实例,然后才能渲染它:

var TestFeed = Backbone.View.extend({ /*...*/ });
var testfeed = new TestFeed();
testfeed.render();

你也在"类"中这样做:

collection : newFeedCollection

这将把newFeedCollection附加到该视图的每个实例,这可能会导致一些令人惊讶的行为。将集合放入视图的常用方法是将其传递给构造函数:

var TestFeed = Backbone.View.extend({ /* As usual but not collection in here... */ });
var testfeed = new TestFeed({ collection: newFeedCollection });
testfeed.render();

视图构造函数将自动将视图的this.collection设置为构建视图时传递的集合。

另一件需要考虑的事情是:

newFeedCollection.fetch();

通常是AJAX调用,所以当你试图渲染它时,你的集合中可能没有任何东西

  1. 视图的render应该能够处理空集合。这主要取决于您的模板是否足够聪明,以便在集合为空时保持理智
  2. 在视图的initialize:中将render绑定到集合的"reset"事件

    initialize: function() {
        this.collection.on('reset', this.render, this);
    }
    

您将遇到的另一个问题是,视图的render正试图渲染this.model:

this.$el.html( compiled_template(this.model.toJSON()) );

当您的视图基于集合时;你想把它改成:

this.$el.html(compiled_template({ tags: this.collection.toJSON() }));

您需要tags,以便在查看集合数据时模板有一个可参考的名称。

此外,您应该能够替换此:

$.each(data.data, function(){
    thisCollection.add(this);
});

只有这个:

thisCollection.add(data.data);

不需要一个接一个地添加它们,Collection#add对一系列模型非常满意。

这里有一个演示,(希望)一切都整理好了:

http://jsfiddle.net/ambiguous/WXddy/

我不得不伪造fetch内部,但其他一切都应该在那里。

testfeed不是实例,而是构造函数。

var instance = new testfeed(); 
instance.render();

可能会起作用(在View定义期间定义el,使其成为原型属性IIRC)。