Динамическое заполнение коллекции на основе ответа JSON от другого URL
Обычно я бэкэнд-парень, работающий над фреймворками и библиотеками J2EE (servlet/ejb). Совершенно новый для front-end и особенно Backbone. Следовательно, вопрос несколько нубский. Буду признателен за любые мнения / учебники / примеры по этому вопросу. Я постараюсь объяснить мою цель / требование как можно более четко и подробно.
Это мой первый вопрос, и поэтому заранее извиняюсь за нарушение каких-либо правил.
В. У меня есть бэкэнд-движок электронной коммерции, который отображает URL-адреса REST как часть API каталога продуктов. API 1 - / остальные / хранилище / atg / коммерция / каталог /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 В основном один из отдельных URL-адресов продукта из ответа API 1 Пример ответа:
{
"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 отвечает с помощью массива JSON, содержащего 4 URL-адреса, т.е. 4 продукта, то мне нужно отобразить атрибуты 4 продуктов в представлении и так далее. Атрибуты можно получить, сделав 4 вызова API 2; другими словами, 4 запроса к URL-адресам, полученным в API 1.
Проблема: я посмотрел несколько уроков и примеров. Я не мог как-то получить что-то в этом конкретном случае использования. Примеры, которые я видел, по сути, предполагают, что будет один 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, установленным на URL API 1. Эта коллекция будет иметь одну модель ProductURLModel, которая будет иметь n число ProductURLModel(s)... n - количество URL-адресов, полученных в API 1, что также эквивалентно количеству продуктов. Это указывает на то, что теперь я должен сделать n вызовов API 2. Для этого я решил сделать еще одну коллекцию ProductCollection, содержащую n номеров ProductModel. Свойство url ProductCollection будет динамически установлено при итерации моделей 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();
});
}
При этом я надеялся, что смогу динамически создавать n ProductModel каждый раз, изменяя url ProductCollectionIns. Однако я получаю сообщение "Ошибка: необходимо указать свойство или функцию URL". Означает ли это, что свойство url ProductCollectionIns не задано?
Я считаю, что в Backbone должен быть более простой способ достичь вышеупомянутого. Пожалуйста, любое решение или лучшая реализация будет оценена.
1 ответ
Позвольте мне объяснить, как работает система AJAX в Backbone, сначала с 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 ищет URL, связанный с Model
, Так как вы никогда не определяли один (или urlRoot
), вы получаете ошибку, потому что Backbone не знает, куда сделать вызов AJAX.
Как только вы сообщите Backbone, где найти данные для этого типа модели через url
Backbone позвонит на сайт www.example.com/5 (поскольку модель имеет id
из 5). Затем Backbone будет ожидать, что этот URL вернет ответ, который выглядит примерно так:
{id: 1, someAttribute: 2, someOtherAttribute: 'spam'}
Что JSON станет someModel
атрибуты, так что вы сможете сделать:
someModel.get('someAttribute'); // == 2
Collection
S работают почти так же, за исключением того, что они ожидают ответ JSON:
[{id: 1, someAttribute: 2, someOtherAttribute: 'spam'},
{id: 2, someAttribute: 55, someOtherAttribute: 'eggs'}]
и они преобразовывают каждый член возвращаемого массива в Model
,
Как вы и предполагали, есть более простой способ, чем ваш populateModels
Метод: если вы просто следуете описанному мной шаблону, ваша коллекция должна создавать модели автоматически, без лишних усилий. Если вам нужно что-то настроить (например, вы хотите изменить атрибут "foo", который приходит с сервера на атрибут "bar"), вы можете перезаписать либо Model
или Collection
"s parse
Метод, который берет "необработанные" данные AJAX и возвращает вашу конвертированную версию:
var someModel = new FooModel({
id: 5,
parse: function(raw) {
raw.bar = raw.foo;
delete raw.foo;
return raw;
}
});
Надеюсь, это поможет.