Предположим, я работаю с API, который возвращает данные JSON, но имеет сложную или переменную структуру. Например, свойство со строковым значением может быть простым литералом или может быть помечено языком:
/* first pattern */
{ "id": 1,
"label": "a foo"
}
/* second pattern */
{ "id": 2,
"label": [ {"value": "a foo", "lang": "en"},
{"value": "un foo", "lang": "fr"}]
}
В моем коде на стороне клиента я не хочу, чтобы код представления беспокоился о том, доступна ли метка на нескольких языках, какой из них выбрать и т. д. Или я мог бы захотеть скрыть подробную структуру JSON по другим причинам. Итак, я мог бы обернуть значение JSON в объект с подходящим API:
/** Value object for foo instances sent from server */
var Foo = function( json ) {
this.json = json;
};
/** Return a suitable label for this foo object */
Foo.prototype.label = function() {
var i18n = ... ;
if (i18n.prefLang && _.isArray(this.json.label)) // ... etc etc
};
Так что все это довольно обычный шаблон объекта-значения, и он полезен, потому что более отделен от конкретного Структура JSON, более проверяемая и т. д. ОК, хорошо.
Чего я в настоящее время не вижу, так это того, как использовать один из этих объектов-значений с Backbone и Marionette. В частности, я хотел бы использовать объект Foo
в качестве основы для Backbone Model
и привязать его к Marionette ItemView
. Однако, насколько я вижу, значения в Model
берутся непосредственно из структуры JSON — я не вижу способа распознать, что объекты являются функциями:
var modelFoo = new Backbone.Model( foo );
> undefined
modelFoo.get( "label" ).constructor
> function Function() { [native code] }
Итак, мой вопрос: каков хороший способ отделить атрибуты Backbone Model
от специфики данной структуры JSON, такой как сложное значение API? Можно ли заставить объекты, модели и представления играть красиво?
Изменить
Позвольте мне добавить еще один пример, поскольку я думаю, что приведенный выше пример, посвященный проблемам i18n, передает только часть моей озабоченности. Несколько упрощая, в моей области есть водоемы, состоящие из рек, озер и приливных зон. С водоемом связана одна или несколько точек отбора проб, и в каждой точке отбора проб имеется самая последняя проба. Это может вернуться из API данных на сервере примерно так:
{"id": "GB12345678",
"centre": {"lat": 1.2345, "long": "-2.3456"},
"type": "river",
"samplingPoints": [{"id": "sp98765",
"latestSample": {"date": "20130807",
"classification": "normal"}
}]
}
Таким образом, в моем коде представления я мог написать такие выражения, как:
<%= waterbody.samplingPoints[0].latestSample.classification %>
or
<% if (waterbody.type === "river") { %>
но это было бы ужасно, и его легко сломать, если изменится формат API. Немного лучше, я мог бы абстрагировать такие манипуляции во вспомогательные функции шаблона, но для них все еще сложно писать тесты. Что я хотел бы сделать, так это иметь класс объекта значения Waterbody
, чтобы мой код представления мог иметь что-то вроде:
<%= waterbody.latestClassification() %>
Одна из основных проблем, с которыми я сталкиваюсь в Marionette, — это настойчивое требование вызова toJSON()
для моделей, передаваемых в представления, но, возможно, в некоторых предложениях вычисляемых свойств есть способ обойти это.
serializeData
в модели. Вы можете манипулировать моделью так, как считаете нужным для представления. - person kalley   schedule 08.08.2013