24

我正在尝试创建一个HtmlHelper将一些 HTML 输出到视图的扩展。在这个 HTML 中,我正在连接一些 KnockoutJS 绑定。我是 KO 的新手,所以我仍然在努力完成一些事情。无论如何,我要做的是在我的客户端代码上生成绑定到可观察对象的输入字段(在服务器端代码中),然后通过隐藏字段的值设置可观察对象的初始值。不幸的是,这对我不起作用。所以我想知道是否有任何方法可以完成这项工作(即使我必须完全不同)。

这就是我基本上在做的事情:

在我的客户端视图模型中,我有以下内容:

self.dataSource = ko.observable();
self.pageSize = ko.observable();

我的扩展方法输出以下内容:

<input type="hidden" value="/Employee/Get" data-bind="value: dataSource" />
<input type="hidden" value="30" data-bind="value: pageSize" />

但是当页面呈现时,当我检查元素时,我注意到value输入字段的 被设置为空字符串,我认为这是因为声明了可观察对象的方式。但是有没有办法覆盖这种行为或什么?

4

4 回答 4

23

这里有点晚了。我实际上对 RP 的回答并不满意,因为它破坏了 Knockout 的声明性。具体来说,如果您使用 valueWithInit 来定义您的属性,则不能在较早的绑定中使用它。这是他的 jsfiddle 的一个分支来演示

您以相同的方式使用它,但它仍然是文档范围内的声明性:

<input data-bind="valueWithInit: firstName" value="Joe" />

扩展这个想法,您还可以使用它来分离初始化和绑定:

<input data-bind="initValue: lastName, value: lastName" value="Smith" />

这有点多余,但当您使用插件而不是内置绑定时会变得很有用:

<input data-bind="initValue: lastName, myPlugin: lastName" value="Smith" />

再扩展一点,我还需要一种初始化复选框的方法:

<input type="checkbox" data-bind="checkedWithInit: isEmployed" checked />

这里是处理程序:

ko.bindingHandlers.initValue = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        if (!ko.isWriteableObservable(value)) {
            throw new Error('Knockout "initValue" binding expects an observable.');
        }
        value(element.value);
    }
};

ko.bindingHandlers.initChecked = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        if (!ko.isWriteableObservable(value)) {
            throw new Error('Knockout "initChecked" binding expects an observable.');
        }
        value(element.checked);
    }
};

ko.bindingHandlers.valueWithInit = {
    init: function(element, valueAccessor, allBindings, data, context) {
        ko.applyBindingsToNode(element, { initValue: valueAccessor() }, context);
        ko.applyBindingsToNode(element, { value: valueAccessor() }, context);
    }
};

ko.bindingHandlers.checkedWithInit = {
    init: function(element, valueAccessor, allBindings, data, context) {
        ko.applyBindingsToNode(element, { initChecked: valueAccessor() }, context);
        ko.applyBindingsToNode(element, { checked: valueAccessor() }, context);
    }
};

注意valueWithInit只是initValue在引擎盖下使用。

在 jsfiddle 上查看它的实际效果。

于 2014-02-11T23:24:02.030 回答
21

您可以用来使代码更简洁的一种替代方法是使用自定义绑定,该绑定通过使用元素的当前值对其进行初始化来包装值绑定。

如果它们不存在,您甚至可以让它在您的视图模型上创建可观察对象。

绑定可能类似于:

ko.bindingHandlers.valueWithInit = {
    init: function(element, valueAccessor, allBindingsAccessor, data) {
        var property = valueAccessor(),
            value = element.value;

        //create the observable, if it doesn't exist 
        if (!ko.isWriteableObservable(data[property])) {
            data[property] = ko.observable();
        }

        data[property](value);

        ko.applyBindingsToNode(element, { value: data[property] });
    }
};

你会像这样使用它:

<input value="someValue" data-bind="valueWithInit: 'firstName'" />

请注意,属性名称用引号引起来,这允许绑定创建它,如果它不存在而不是从未定义的值中出错。

这是一个示例:http: //jsfiddle.net/rniemeyer/BnDh6

于 2012-08-27T03:03:33.660 回答
2

如果自定义绑定太重,那么一个简单的解决方案是从 DOM 初始化可观察对象。

例如,给定以下 HTML 表单:

<form name="person">
  <input type="text" name="firstName" value="Joe" data-bind="value: firstName"/>
</form>

然后 Knockout 可以如下初始化:

ko.applyBindings({
  firstName: ko.observable(document.forms['person']['firstName'].value)
});
于 2017-01-01T22:22:10.007 回答
1

您可以简单地使用自定义绑定并将值分配给现有的 observables:

ko.bindingHandlers.yourBindingName = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        viewModel.dataSource($(".dataSource").val());
        viewModel.pageSize($(".pageSize").val());
    }
};

data-bind="yourBindingName"然后,只需向输入和包含它们的 HTML 元素添加一个类或一个 Id 。

于 2017-07-07T07:36:45.970 回答