【问题标题】:Giving initial value to observable from the HTML markup从 HTML 标记中为 observable 赋予初始值
【发布时间】:2012-08-20 22:43:57
【问题描述】:

我正在尝试创建一个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 被设置为空字符串,我认为这是因为声明了可观察对象的方式。但是有没有办法覆盖这种行为?

【问题讨论】:

  • 您可以用来保持代码更简洁的另一种方法是使用自定义绑定,该绑定通过使用元素的当前值对其进行初始化来包装value 绑定。如果不存在,您甚至可以让它在您的视图模型上创建可观察对象。这是一个示例:jsfiddle.net/rniemeyer/BnDh6
  • 嗯...现在我得到了在发出的 HTML 标记中显示的值,但 observables 的值仍未定义。
  • 你能在 jsFiddle 里放点东西吗?
  • 没关系,我搞定了。这是一个愚蠢的错误(像往常一样!)。您能否发布您的答案,以便我接受它作为正确的答案?感谢您的帮助,非常感谢:)

标签: javascript data-binding knockout.js observable


【解决方案1】:

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

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

绑定可能类似于:

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

【讨论】:

  • 其实属性名不带引号是不行的。
  • 是的,这个版本的绑定要求名称用引号括起来。如果你知道你的 observables 已经存在,那么你可以直接绑定它们,并简单地在 init 函数中根据元素的值设置 observable 的值。
  • 我过去曾使用过它,我想补充一点,通过将ko.applyBindingsToNode(element, { value: data[property] }); 更改为ko.applyBindingsToNode(element, { textInput: data[property] }); 可以让您实时双向更新. knockoutjs.com/documentation/textinput-binding.html
【解决方案2】:

这里有点晚了。我实际上对 RP 的回答并不满意,因为它破坏了 Knockout 的声明性。具体来说,如果你使用 valueWithInit 来定义你的属性,你就不能在之前的绑定中使用它。这是fork of his jsfiddle to demonstrate

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

<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

in action on jsfiddle

【讨论】:

  • 警告:initValue 绑定必须在值(或任何其他值更改)绑定之前
  • 值得一提的是,isModified() 将设置为 true,因此如果您不希望发生这种情况,我们需要在设置值后将其设置为 false。像这样“valueAccessor().isModified(false)”
【解决方案3】:

如果自定义绑定过于繁重,那么一个简单的解决方案是从 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)
});

【讨论】:

    【解决方案4】:

    您可以简单地使用 custom binding 并将值分配给现有的 observable:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-03
      • 2019-09-22
      • 1970-01-01
      • 2018-05-04
      • 2014-05-25
      • 2022-01-23
      • 2012-07-16
      • 1970-01-01
      相关资源
      最近更新 更多