Привязка свойства, которое может иметь несколько типов данных в Knockout

Так что у меня есть пользовательская привязка нокаута для обработки продолжительности времени. У меня есть проблема, когда значение в одной из моих форм может быть продолжительностью, но также может быть строкой или другим значением. Проблема возникает из-за того, что значения продолжительности представлены в виде объектов с двумя свойствами: duration и time_unit (который сам является объектом с двумя свойствами. У меня есть различные связанные узлы, связанные внутри, если есть привязки.

init: function(element, valueAccessor, allBindingsAccessor, viewModel, context) {

    var allBindings = ko.toJS(allBindingsAccessor() || {}),
        source = allBindings.source || [],
        observable = valueAccessor(),
        value = ko.toJS(ko.utils.unwrapObservable(observable)),

        duration = new DurationControl({
            inputNode: inputNode,
            source: source,
            defaultValue: value
        });

    //attach duration control to element and render here

    ko.utils.registerEventHandler(inputNode.getDOMNode(), 'blur', function () {
        var observable = valueAccessor();

        if (!observable.viewModelUpdating) {
            observable.viewModelUpdating = ko.observable(false);
        }

        if (duration.isValueValid(true)) {
            observable.viewModelUpdating(true);
            observable.duration(duration.getDuration());
            observable.time_unit.value(duration.getTimeUnit());
            observable.time_unit.id(sourceIdValueMap[duration.getTimeUnit()] || 0);
            observable.viewModelUpdating(false);
        }
    });
}

И мой связанный HTML

<!-- ko if: type() == 'string' -->
<div class="control wide">
    <input type="text" data-bind="value: value" />
</div>
<!-- /ko -->

<!-- ko if: type() == 'duration' -->
<div class="control">
   <input type="text" data-bind="duration: value, source: metadata.time_units" />
</div>
<!-- /ko -->

Если я делаю начальную привязку со значением, являющимся правильным форматом объекта, как так

...,
value: {
    duration: '',
    time_unit: {
        value: '',
        id: '',
    }
},
...

все отлично работает Но если я начну со значения в каком-то другом формате, например ..., value: 'nada', ... это прерывает попытку доступа к observable.duration (и observable.time_unit.*).

Когда я оцениваю значение с правильной настройкой, я получаю объект, описанный выше, обратно. Если я попытаюсь вручную добавить свойства duration / time_unit в качестве наблюдаемых, я все равно просто получу пустую строку обратно.

Как мне лучше всего обновлять viewmodel / bindings / etc внутри моей функции init, чтобы она вела себя так, как будто модель изначально находилась в этом состоянии, когда я ее инициализировал?

1 ответ

Решение

Пользовательская привязка не является решением вашей проблемы. Knockout свяжет все, с чем он сталкивается в DOM, поэтому, с каким бы типом объекта вы ни инициализировали свое значение, другой не получится. Я реализовал нечто подобное, когда наблюдаемая в моей модели представления хранит несколько "типов" объектов, для которых вам понадобятся "специфичные для типа" части пользовательского интерфейса, привязанные к каждому. Вот как я решил проблему:

Удалить все экземпляры, if: type() == '<type>' и реализовать каждый кусок HTML в качестве шаблона.

Теперь рефакторинг этого процесса принятия решений. Используйте вычисляемую наблюдаемую информацию, чтобы решить, какой шаблон будет показан на основе type(), Что-то вроде этого...

function ViewModel(){
    var self = this;

    self.type = ko.observable();
    self.value = ko.observable();

    self.currentValueTemplate = ko.computed(function(){
       switch(self.type()) {
           case 'string':
               return 'stringTemplate';

           case 'duration':
               return 'durationTemplate';

           default:
               throw 'invalid type';
       }
    });

Теперь просто добавьте шаблон заполнителя...

<!-- ko template: { name: currentValueTemplate, data: value } -->
<!-- /ko -->

Возможно, вы захотите адаптировать это в соответствии со спецификой вашего приложения, но это более аккуратный подход, и он будет масштабироваться намного лучше, если вы захотите хранить растущее разнообразие типов объектов.

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