9

单击表单重置按钮时,Knockout 不会更新 observables。

http://jsfiddle.net/nQXeM/

HTML:

<form>
    <input type="text" data-bind="value: test" />
    <input type="reset" value="reset" />
</form>
<p data-bind="text: test"></p>

JS:

function ViewModel() {
    this.test = ko.observable("");
}

ko.applyBindings(new ViewModel());

显然输入框的更改事件没有被触发,正如这个 jQuery 测试所见:http: //jsfiddle.net/LK8sM/4/

如果重置按钮没有触发更改事件,我们将如何强制所有绑定到表单输入的可观察对象进行更新,而无需手动指定它们?

使用 jQuery 来查找表单内的所有输入并触发更改事件很容易,但假设我们有一个仅淘汰赛控制的表单。

4

2 回答 2

3

我复制并修改了默认的 Knockout 提交绑定,以便为表单重置事件创建类似的绑定:

ko.bindingHandlers['reset'] = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        if (typeof valueAccessor() !== 'function')
            throw new Error('The value for a reset binding must be a function');

        ko.utils.registerEventHandler(element, 'reset', function (event) {
            var handlerReturnValue;
            var value = valueAccessor();

            try {
                handlerReturnValue = value.call(bindingContext['$data'], element);
            } finally {
                if (handlerReturnValue !== true) {
                    if (event.preventDefault)
                        event.preventDefault();
                    else
                        event.returnValue = false;
                }
            }
        });
    }
};

你会这样绑定:

<form data-bind="reset: onFormReset">

并将onFormReset在您的视图模型上:

function ViewModel() {
    this.onFormReset = function () {
        //Your custom logic to notify or reset your specific fields.

        return true;
    }
}

在您的重置处理程序中,如果您返回 true,那么 JavaScript 将继续在表单上调用其重置函数。但是,如果您正在设置绑定到 value 的 observable,则实际上不需要让 JavaScript 继续重置表单。因此,从技术上讲,您可以不返回任何内容,或者在这种情况下返回 false。

其他人可以进一步扩展它以自动通知表单中所有绑定的 observables,但这符合我的目的。

于 2015-02-05T16:24:25.537 回答
1

正如您所提到的,change重置表单时不会触发该事件。如果您只使用 KnockOut,我认为您真的没有可能的选择,除非您创建可以注册reset事件并检测更改的自定义绑定 - 这仍然涉及手动 JS,但至少它将是集中式的。

一种更通用的方法,虽然它确实需要 jQuery,但它是创建一个函数来处理表单的reset事件,并检测当时表单输入的变化。

这是一个可能有效的事件处理程序示例。请注意,这不是生产就绪代码。在使用之前,我会用一个好的 jQuery 眼光看它:)

$('form').on('reset', function (evt) {
    evt.preventDefault();
    $(this).find('input, select, textarea').each(function () {
        if ($(this).is('input[type="radio"], input[type="checkbox"]')) {
            if ($(this).is(':checked') !== $(this)[0].defaultChecked) {
                $(this).val($(this)[0].defaultChecked);
                $(this).trigger('click');
                $(this).trigger('change');
            }
        } else {
            if ($(this).val() !== $(this)[0].defaultValue) {
                $(this).val($(this)[0].defaultValue);
                $(this).change();
            }
        }
    });
});

这是一个演示这个想法的小提琴:http: //jsfiddle.net/Fm8rM/2/

于 2013-04-09T06:08:50.597 回答