【问题标题】:Binding a property that could be of multiple data types in Knockout在 Knockout 中绑定可能是多种数据类型的属性
【发布时间】:2013-11-18 07:44:02
【问题描述】:

所以我有一个自定义的淘汰赛绑定来处理持续时间。我有一个问题,我的一个表单中的值可能是一个持续时间,但也可能是一个字符串或其他值。问题在于持续时间值表示为具有两个属性的对象,持续时间和 time_unit(它本身就是一个具有 2 个属性的对象。我将各种绑定节点绑定在 if 绑定中。

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 属性添加为 observables,我仍然只是将空字符串取出。

我如何最好地从我的 init 函数中更新 viewmodel/bindings/etc,以便它的行为就像我初始化模型时最初处于该状态一样?

【问题讨论】:

  • 在视图中,您似乎有一个 type() 可观察对象,它知道该值是持续时间还是字符串。如果 type() == 'string' ,你不能在 customBinding 中使用它并做不同的事情吗?
  • 我可以,这是我备份计划的一部分。如果必须的话,我可以有多个值类型的可观察对象(durationValue、stringValue、dateValue 等),并且可以计算出根据类型获取适当值的值,但是如果我能解决这个问题,我可以避免重复所有这些代码(可能稍微修改)在许多地方,只是让它由绑定处理,简单地绑定到可观察的值。
  • 你试图不复制的代码是什么?
  • 此自定义绑定可用于许多不同的地方/视图模型。我已经有 2 个地方出现了这个问题。使用此 vm 的解决方法,我必须打开类型并返回适当的绑定值,但每个 vm 会有所不同。能够解决这个问题将允许我简单地绑定到 vm 并绕过每个 vm 中的计算逻辑。
  • 但是即使你检测到viewModel的类型,你不是必须在customBinding里面有一个switch来根据类型做不同的事情吗?抱歉,如果我没有正确理解问题,这里有点晚了。

标签: javascript knockout.js templatebinding computed-observable


【解决方案1】:

自定义绑定不能解决您的问题。 Knockout 将绑定它在 DOM 中遇到的所有内容,因此无论您使用哪种类型的对象初始化值,另一种都将失败。我已经实现了类似的东西,其中我的视图模型中的可观察对象存储了多种“类型”的对象,您需要将 UI 的“类型特定”部分绑定到每个对象。这就是我解决问题的方法:

删除 if: type() == '&lt;type&gt;' 的所有实例,并将每段 HTML 实现为 template

现在重构决策过程。使用computed observable 根据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 -->

您可能希望对其进行调整以适应您的应用程序的具体情况,但这是一种更简洁的方法,并且如果您希望存储越来越多的对象类型,它的扩展性会更好。

【讨论】:

    猜你喜欢
    • 2021-08-12
    • 1970-01-01
    • 2014-02-21
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    • 2020-04-25
    • 2018-09-21
    相关资源
    最近更新 更多