Привязка свойства, которое может иметь несколько типов данных в 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 -->
Возможно, вы захотите адаптировать это в соответствии со спецификой вашего приложения, но это более аккуратный подход, и он будет масштабироваться намного лучше, если вы захотите хранить растущее разнообразие типов объектов.