Как связать глубже одного уровня с rivets.js
rivets.js новичок здесь. Я хочу привязать к элементу, который будет динамически изменяться (store.ActiveItem). Я попробовал следующий подход, но хотя store.ActiveItem установлен, store.ActiveItem. (Любое свойство) всегда неопределен. Есть ли стандартный способ привязки глубже, чем один уровень?
<div id="editItemDialog" data-modal="store.ActiveItem < .ActiveItem">
<a data-on-click="store:ClearActiveItem" href="#">close - works</a>
<div>
<div>
<label>name:</label><input data-value="store.ActiveItem.Name < .ActiveItem"/>
</div>
<div>
<label>price:</label><input data-value="store.ActiveItem.Price < .ActiveItem"/>
</div>
<div>
<label>description:</label><textarea data-value="store.ActiveItem.Description < .ActiveItem"></textarea>
</div>
</div>
</div>
1 ответ
Как работает переплет, во многом определяется адаптером Rivets, который вы используете, хотя ваша модель также может выполнять тяжелую работу.
Вариант 1: умная модель
Если вы используете Backbone.js, вы можете взглянуть на backbone-deep-model, который поддерживает синтаксис пути для вложенных атрибутов (например, store.get('ActiveItem.Price')
), хотя он все еще находится в стадии разработки. Если это не совсем соответствует вашим потребностям, в вики-плагинах и расширениях Backbone есть и другие варианты вложенных моделей.
Вариант 2: интеллектуальный адаптер
Если это не работает для вас, вы можете расширить свой адаптер Rivets для обработки синтаксиса пути. Я собрал простой пример того, как это сделать, по адресу http://jsfiddle.net/zKHYz/2/ со следующим наивным адаптером:
rivets.configure({
adapter: {
subscribe: function(obj, keypath, callback) { /* Subscribe here */ },
unsubscribe: function(obj, keypath, callback) { /* Unsubscribe here */ },
read: function(obj, keypath) {
var index = keypath.indexOf('.');
if (index > -1) {
var pathA = keypath.slice(0, index);
var pathB = keypath.slice(index + 1);
return obj[pathA][pathB];
} else {
return obj[keypath];
}
},
publish: function(obj, keypath, value) {
var index = keypath.indexOf('.');
if (index > -1) {
var pathA = keypath.slice(0, index);
var pathB = keypath.slice(index + 1);
return obj[pathA][pathB] = value;
} else {
return obj[keypath] = value;
}
}
}
});
Вариант 3: грязные хаки
Начиная с версии 0.3.2, Rivets поддерживает связывание итераций. Создав форматировщик Rivets, который возвращает массив, вы можете "перебирать" свое свойство. Посмотрите на http://jsfiddle.net/mhsXG/3/ для рабочего примера этого:
rivets.formatters.toArray = function(value) {
return [value];
};
<div data-each-item="store.ActiveItem | toArray < store.ActiveItem"">
<label>name:</label><input data-value="item.Name < store.ActiveItem"/>
...
</div>
Я не уверен, требуется ли здесь синтаксис вычисляемого свойства; вам придется проверить это с вашей моделью, чтобы увидеть, что работает.
Вариант 4: не связывать глубже, чем один уровень (рекомендуется)
Необходимость привязки глубже одного уровня может указывать на то, что ваш дизайн может быть улучшен.
В вашем примере у вас есть список Предметов в ItemCollection для Магазина. Вы идете о назначении отдельного элемента свойству ActiveItem магазина, настраиваете события повсюду, чтобы попытаться связать вещи вместе, а затем вам нужно иметь возможность привязываться к свойствам ActiveItem в хранилище, но все же обновлять вещи при каждом изменении самого ActiveItem., так далее..
Лучший способ сделать это - использовать подход "просмотр по модели". В вашем примере вы пытаетесь обработать модель магазина, коллекцию элементов и модель элементов с помощью одного представления. Вместо этого вы можете иметь родительское представление Store, подпредставление для ItemCollection и затем генерировать представления Item, если это необходимо. Таким образом, представления легче создавать и отлаживать, они менее тесно связаны с общим дизайном модели и более легко используются во всем приложении. В этом примере это также упрощает дизайн модели, поскольку вам больше не нужно свойство ActiveItem в хранилище, чтобы пытаться поддерживать состояние; вы просто привязываете вид элемента к выбранной модели элемента, и все освобождается с помощью вида элемента.
Если вы используете Backbone.js, посмотрите на Backbone.View в качестве отправной точки; в Интернете есть много примеров, хотя я буду первым, кто признает, что все может стать несколько сложным, особенно если у вас есть вложенные представления. Я слышал хорошие отзывы о Backbone.LayoutManager и о том, как он уменьшает эту сложность, но у меня еще не было возможности использовать его самостоятельно.
Я изменил ваш последний пример, чтобы использовать сгенерированные представления элементов по адресу http://jsfiddle.net/EAvXT/8/, и соответственно покончил со свойством ActiveItem. Хотя я не разделял представление Store из представления ItemCollection, учтите, что я передаю их модели в заклепки отдельно, чтобы избежать необходимости привязки к store.Items.models
, Опять же, это довольно наивный пример, который не обрабатывает полный жизненный цикл представления, например, отменяет привязку заклепок при удалении вида.