Backbone基于来自另一个URL的JSON响应动态填充集合

时间:2014-10-06 08:57:39

标签: backbone.js backbone.js-collections

我通常是从事J2EE(servlet / ejb)框架和库的后端人员。全新的前端,尤其是Backbone。因此,问题有点像菜鸟。我会很感激任何意见/教程/例子。我将尽可能清楚,精细地解释我的目标/要求。

这是我的第一个SO问题,因此提前为违反任何规则道歉。

Q值。我有一个后端电子商务引擎,它将REST URL作为产品目录API的一部分公开。 API 1 - / rest / repository / atg / commerce / catalog / ProductCatalog / product /。 API 1将产品列表作为单个JSON数组进行响应。这里有趣的是,它只为每个产品发送单独的REST URL。样品响应:

{"product": [
  "http://example.com/rest/repository/atg/commerce/catalog/ProductCatalog/product/prod90004",
  "http://example.com/rest/repository/atg/commerce/catalog/ProductCatalog/product/prod90005",
  "http://example.com/rest/repository/atg/commerce/catalog/ProductCatalog/product/prod100027"
  "http://example.com/rest/repository/atg/commerce/catalog/ProductCatalog/product/prod70011",
  "http://example.com/rest/repository/atg/commerce/catalog/ProductCatalog/product/prod70013"
]}

API 2 - http://example.com/rest/repository/atg/commerce/catalog/ProductCatalog/product/ productId 即。 http://example.com/rest/repository/atg/commerce/catalog/ProductCatalog/product/prod90004 基本上是API 1响应中的单个产品URL之一 样品响应:

{
  "dateAvailable": "2000-05-04 15:51:42.521",
  "displayName": "Warm Black Gloves ",  
  "longDescription": "Protects you from the elements and keeps you looking good, these durable gloves won't let you down.",
  "repositoryId": "prod90004"
}

必需目标:如果API 1使用包含4个URL(即4个产品)的JSON数组作出响应,那么我需要在视图中显示4个产品的属性,依此类推。可以通过对API 2进行4次调用来检索属性;换句话说,对API 1中收到的URL发出4个请求。

问题: 我已经研究了一些教程和示例。我无法以某种方式获得有关此特定用例的任何内容。我已经看到的示例假设将有一个REST API,它将使用包含所有模型(在这种情况下为产品)的JSON数组及其属性在单个JSON响应中进行响应。但是,这不是这种情况,因为我必须首先调用API 1来获取产品URL列表,然后调用所有这些URL(在API 1的响应中检索)以获取相应模型的属性。因此,我无法决定如何定义模型,集合和URL属性等。

我试过如下:

(function ($) {

    var ProductView = Backbone.View.extend({

        tagName:"div",
        className:"bookContainer",
        template:$("#bookTemplate").html(),

        render:function () {
            console.log("inside render of ProductView");
            var tmpl = _.template(this.template); 
            this.$el.html(tmpl(this.model.toJSON())); 
            return this;
        }
    });

    var ProductModel = Backbone.Model.extend({

        defaults:{
            displayName:"displayName",
            longDescription:"longDescription",
            dateAvailable:"dateAvailable",
            repositoryId:"repositoryId",
        },

        initialize: function(){
            this.on("reset", this.renderModelView, this);
            this.fetch({
                reset:true,
                error:function () {
                    console.log(arguments);
                }
            });

        },

        renderModelView: function(){
            var that = this;
            new ProductView.render({
                    model: that
                });

        }
    });

    var ProductCollection = Backbone.Collection.extend({
        model: ProductModel,

        initialize: function(){
            this.on("reset", this.debugTempfunc, this);
            this.fetch({
                reset:true,
                error:function () {
                    console.log(arguments);
                }
            });
        },

        debugTempfunc: function(){
            console.log("collection length: "+this.length);
        }
    });

    var ProductURLModel = Backbone.Model.extend({   

        defaults:{
            product: "ProductCatalogProductURLs"
        }       

    });

    var ProductURLCollection = Backbone.Collection.extend({
        model: ProductURLModel,

        url: "http://example.com/rest/repository/atg/commerce/catalog/ProductCatalog/product",

        initialize: function(){
            this.on("reset", this.populateModels, this);
            this.fetch({
                reset:true,
                error:function () {
                    console.log(arguments);
                }
            });
        },

        populateModels: function(){
            var ProductCollectionIns = new ProductCollection();

            var that = this;
            console.log("inside populateModels of ProductURLCollection: "+that);
            _.each(that.models[0].attributes.product,function(item){
                console.log("populateModels, item value: "+item);
                ProductCollectionIns.url=item;
                ProductCollectionIns.fetch();

            });

        }       

    });

    var ProductURLCollectionTestIns = new ProductURLCollection();

})(jQuery);

我的计划是首先将ProductURLCollection定义为一个集合,其URL设置为API 1的URL。此集合将具有单个模型ProductURLModel,其将具有n个ProductURLModel(s)... n是在API 1中检索的URL的数量,其也等同于产品的数量。这表明现在我必须进行n次API 2调用。为此,我决定制作另一个包含n个ProductModel的集合ProductCollection。 ProductCollection的url属性将在迭代ProductURLCollection模型时动态设置,如下面的代码所示:

populateModels: function(){
            var ProductCollectionIns = new ProductCollection();

            var that = this;
            console.log("inside populateModels of ProductURLCollection: "+that);
            _.each(that.models[0].attributes.product,function(item){
                console.log("populateModels, item value: "+item);
                ProductCollectionIns.url=item;
                ProductCollectionIns.fetch();

            });

        }

有了这个,我希望每次更改ProductCollectionIns url时都可以动态生成n个ProductModel。但是,我得到“错误:必须指定”url“属性或函数”。这是否意味着没有设置ProductCollectionIns url属性?

我相信必须有一种更简单的方法来实现Backbone中的上述功能。请赞赏任何解决方案或更好的实施方案。

1 个答案:

答案 0 :(得分:2)

让我解释一下Backbone的AJAX系统是如何工作的,首先是Model(但我会在一分钟内到达Collection)。简而言之,Backbone旨在让您能够做到:

var FooModel = Backbone.Model.extend({url: 'www.example.com'});

var someModel = new FooModel({id: 5});
someModel.fetch().done(function() {
    // Now someModel should be populated with the AJAX data for model #5
});

在幕后发生的事情当你致电fetch时,Backbone会查找与Model相关联的网址。由于您从未定义过一个(或urlRoot),因此您会收到错误,因为Backbone不知道在哪里进行AJAX调用。

一旦您通过url属性告知Backbone在哪里可以找到该类型模型的数据,Backbone将会调用www.example.com/5' (因为模型的id为5)。然后Backbone将期望该URL返回类似于以下内容的响应:

{id: 1, someAttribute: 2, someOtherAttribute: 'spam'}

JSON将成为someModel的属性,因此您可以做到:

someModel.get('someAttribute'); // == 2

Collection的工作方式几乎相同,只是他们期望JSON响应为:

[{id: 1, someAttribute: 2, someOtherAttribute: 'spam'},
 {id: 2, someAttribute: 55, someOtherAttribute: 'eggs'}]

并将返回数组的每个成员转换为Model

正如您所推测的,有一种比populateModels方法更简单的方法:如果您只是遵循我描述的模式,您的收藏应该自动创建模型而不需要额外的努力。如果您确实需要自定义内容(例如,您想要将来自服务器的" foo"属性更改为" bar"属性),则可以覆盖{{1} }'或Model' Collection方法,它采用" raw" AJAX数据并返回转换后的版本:

parse

希望有所帮助。