Как связать глубже одного уровня с 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, Опять же, это довольно наивный пример, который не обрабатывает полный жизненный цикл представления, например, отменяет привязку заклепок при удалении вида.

Другие вопросы по тегам