【问题标题】:Backbone: Collection is empty when view is initializedBackbone:初始化视图时集合为空
【发布时间】:2014-06-06 21:50:45
【问题描述】:

我一直在努力寻找解决这个问题的方法,但我认为我的模式是错误的。

我不知道如何使用collection.fetch() 来获取初始渲染的数据。

我正在调用 Flickr API 来构建一些图像。单击按钮时,应将下一页值传递给collection.url,并提交一个新的 ajax 请求以重新呈现模板。但是,我无法让集合从 Flickr 中提取数据并将其传递给初始渲染时的模板。

这是我当前代码的一个小提琴:http://jsfiddle.net/48WpV/

这是我的 JavaScript:

var urlParameters = {
  page: 1,
  api_key:'a2978e5ce30c337e3b639172d3e1a0d1',
  tags: 'cats',
  method: 'flickr.photos.search',
  per_page: 3,
  format: 'json'
};

var TheModel = Backbone.Model.extend({
  default: {
    photos: '',
    stat: ''   
  }
});

var TheCollection = Backbone.Collection.extend({
  model: TheModel,

  url: 'http://api.flickr.com/services/rest'

});

var TheView = Backbone.View.extend({
  el: '.js-container',

  initialize: function () {
    this.collection = new TheCollection();

    this.fetchData();

    this.listenTo(this.collection, 'change', this.render);

    return this;
  }, 

  render: function () {        
    var temp = _.template( $('#List').html(), {collection: this.collection.toJSON()} );      
    this.$el.html(temp);   

    return this;
  },

  fetchData: function () {
    var self = this;
    this.collection.fetch({
        type: 'GET',
        dataType:'jsonp',
        data: urlParameters,
        jsonp:'jsoncallback',
        success: function (data) {
           console.log('self.collection =',self.collection.toJSON()); 
        },
        error: function () {
            console.log('ERROR!!!');
        }
    });    

    return this;
  },

  events: {
    'click .js-button': 'nextPage'   
  },

  nextPage: function () {
    urlParameters.page = urlParameters.page + 1;
    this.fetchData();

    return this;
  }

});

var theView = new TheView();
theView.render();

这是我的 HTML:

<script type="text/template" id="List">
    <button class="js-button">Click for the next page</button>
    <% console.log('templates collection=',collection) %>

    <% _.each(collection, function (element, index) { %>
        <% _.each(element.photos.photo, function(ele, i) { %>

           <img src="http://farm<%- ele.farm %>.staticflickr.com/<%- ele.server %>/<%- ele.id %>_<%- ele.secret %>_m.jpg" />

        <% }); %>

    <% }); %>

</script>


<div class="js-container">

</div>

【问题讨论】:

  • (1) fetch 是一个 AJAX 调用,您必须等到它完成后才能对其结果执行任何操作。 (2) self.collection = data 没有任何作用,data 应该已经是集合,fetch 就地更新集合。
  • @muistooshort 谢谢你的解释。我不清楚集合是否会在获取后更新,或者我是否必须重新分配响应的值。
  • 我重新打开是因为您有两个问题:AJAX 问题和url 问题。
  • 仅供参考,如果您想将其他数据保留在内存中(或者因为您想一次显示所有数据,或者因为您希望用户能够返回并避免重新获取较早的数据),将remove: false 放入您的fetch 参数中。然后它只会添加新模型并合并现有模型。
  • 您可以this.listenTo(this.collection, 'reset', this.render) 然后用reset: true 调用fetch。类似于这个版本的拉米小提琴:jsfiddle.net/ambiguous/gu8v5。或者你可以移动一些东西并这样做:jsfiddle.net/ambiguous/8993M

标签: javascript jquery backbone.js underscore.js


【解决方案1】:

我在您的代码中发现了以下问题:

1) 您需要在每次获取时更新 url。

fetchData: function () {
    var self = this;
    this.collection.fetch({
        url: 'http://api.flickr.com/services/rest/?page=' + pageNumber + '&api_key=a2978e5ce30c337e3b639172d3e1a0d1&tags=kitten&method=flickr.photos.search&per_page=3&format=json&jsoncallback=?',
        type: 'GET',
        success: function (data) {
           self.collection = data; 
        },
        error: function () {
            console.log('ERROR!!!');
        }
    });    

2) 您需要从您的网址中删除“1”

url: 'http://api.flickr.com/services/rest/?page=' + pageNumber + '1&api_key=a2978e5ce30c337e3b639172d3e1a0d1&tags=kitten&method=flickr.photos.search&per_page=3&format=json&jsoncallback=?

成为

  url: 'http://api.flickr.com/services/rest/?page=' + pageNumber + '&api_key=a2978e5ce30c337e3b639172d3e1a0d1&tags=kitten&method=flickr.photos.search&per_page=3&format=json&jsoncallback=?'

3) 您需要将pageNumber + 1; 更改为pageNumber += 1; 才能实际增加值。

4) 你不会在这一行 self.collection = data; 单独调用 fetch() 将返回的值分配给集合。

5) 当然,你需要在每次获取后渲染

这是一个工作代码:http://jsfiddle.net/48WpV/7/

【讨论】:

  • 您的小提琴仍然无法正常工作,因为fetch 是一个 AJAX 调用,并且没有任何东西在监听它生成的任何事件。您需要在fetch 选项中包含reset:true,并将render 绑定到'reset' 事件。
  • @muistooshort 我想我正试图让他的代码同步工作(它现在工作)。遵循您的方法可能比每次获取后调用 render 更干净,但我会将其留给 OP 根据您的评论更新代码。谢谢。
  • @谢谢拉米!我为代码中的其他错误道歉,这是我不确定的提取,所以没有注意到其他错误。谢谢!
  • @RamiEnbashi 我一定误解了 collection.url。我认为var pageNumber 会在第一次单击后在 collection.url 中将该值更新为 2。也感谢您的其他建议。我全神贯注于找出获取方法,以至于我没有注意到它们。