Knockout doesn't update observables when a form reset button is clicked.
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());
Clearly the change event of the input box isn't being fired, as seen with this jQuery test: http://jsfiddle.net/LK8sM/4/
How would we go about forcing all observables bound to form inputs to update without having to manually specify them if the reset button isn't firing of change events?
It would be easy enough to use jQuery to find all inputs inside the form and trigger change events, but lets assume we've a knockout only controlled form.
I copied and modified the default Knockout submit binding in order to create a similar binding for the form reset event:
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;
}
}
});
}
};
You'd bind this like:
<form data-bind="reset: onFormReset">
and onFormReset
would be on your view model:
function ViewModel() {
this.onFormReset = function () {
//Your custom logic to notify or reset your specific fields.
return true;
}
}
In your reset handler, if you return true, then JavaScript will continue to call its reset function on the form. If you are setting observables that are bound to value, though, you don't really need to have JavaScript continue to reset the form. Therefore, you could technically not return anything, or return false in that scenario.
Someone else could extend this further to notify all the bound observables in the form automatically, but this worked for my purposes.
As you mentioned, the change
event isn't fired when a form is reset. If you're only using KnockOut, I don't think you really have may options unless you create custom bindings that can register for the reset
event and detect changes - that would still involve manual JS, but at least it would be centralized.
A more general approach, although it does require jQuery, is to create a function to handle the form's reset
event, and detect changes on the form inputs at that time.
Here's an example of an event handler that might work. Please be aware, this is not production-ready code. I would look at it with a good jQuery eye before using :)
$('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();
}
}
});
});
Here's a fiddle that demonstrates the idea: http://jsfiddle.net/Fm8rM/2/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With