Checkbox change event issue with Internet Explorer 11

1,668 views
Skip to first unread message

Bob Wirka

unread,
May 30, 2016, 1:02:14 AM5/30/16
to KnockoutJS
This web page works as expected on Chrome and Firefox (in Windows and Linux). It does not work in IE11.

It appears that the 'checked' status of the check box is updated AFTER the 'change' event occurs; but only on IE11. This results in 'checked' being shown in the edit box when the check box is unchecked, and vice versa.

The only solution I've found is, instead of using the observable boolean value,  to use the check box itself and query it's 'checked' property: $('#CheckBox').prop('checked').

Here is the test web page:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--This is needed just to get this page to load on IE11-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">

<title>Check Box Issue</title>

<script type='text/javascript' src='https://code.jquery.com/jquery-2.2.4.min.js'></script>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js'></script>

</head>
<body>

<p>Click check box to toggle text</p>
<input id="CheckBox" type="checkbox" data-bind="checked:box,event:{change:boxChange}"><input type="text" data-bind="value:val">

<script>
var KoCheckboxIssue = (function () {
function KoCheckboxIssue() {
var self = this;
self.box = ko.observable(false);
self.val = ko.observable('Unchecked');
ko.applyBindings(self);
}
KoCheckboxIssue.prototype.boxChange = function () {
var self = this;
if (self.box()) {
self.val('Checked');
}
else {
self.val('Unchecked');
}
};
return KoCheckboxIssue;
}());
var koCheckboxIssue;
$(document).ready(function () {
koCheckboxIssue = new KoCheckboxIssue();
});
</script>

</body>
</html>

Does anyone know if there's a way to use the observable as shown?

Thanks.

PS: That JavaScript was generated from TypeScript.

Ian Yates

unread,
May 30, 2016, 8:41:07 AM5/30/16
to KnockoutJS
You're not really writing things the "knockout way", or even the MVVM way.  There's a fundamental race condition evident in the code as the behaviour would change depending on whether KO's checked binding did it's work before or after the event binding did it's work.

I think you're trying to have val indicate "checked" if box is true and "unchecked" if box is false.  Why not just use a computed?  Any time you're relying on some UI control to act as the bridge between updating two parts of your view model you're potentially going to run into these strange issues.

Is there something more complicated you're trying to achieve?  If so, some combination of subscribe, or a more complicated computed expression, may still be the answer.

Bob Wirka

unread,
May 30, 2016, 11:41:27 AM5/30/16
to KnockoutJS
Ian,

Thanks for your reply.

Yes, I'll cop to the code kluge. I'm relatively new to this, and still trying to figure things out.

You are correct, it is a little more complicated. I'm actually implementing a dynamic array of identical <div>'s on the page; each with their own data. I had been using the 'event' binding on the check box to trigger changes in the underlying data model and hence, the displayed data. The 'foreach' approach appears to work. Will pursue this in the (more complex) actual web page.

Here is a version that works with Chrome, Firefox, and IE:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--This is needed just to get this page to load on IE11-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">

<title>Check Box Issue</title>

<script type='text/javascript' src='https://code.jquery.com/jquery-2.2.4.min.js'></script>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js'></script>

   <!--<script type='text/javascript' src='KoCheckboxIssue.js'></script>-->

</head>
<body>

<p>Click check box to toggle text</p>

<div data-bind="foreach:boxVal">
<input type="checkbox" data-bind="checked:$data.box"><input type="text" data-bind="value:$data.txt"><br>
</div>

<script>
/**
* Created by rcw on 5/29/16.
*/
/// <reference path="jquery.d.ts"/>
/// <reference path="knockout.d.ts"/>
/*
* Data model.
*/
var DataModel = (function () {
function DataModel(b, v) {
var self = this;
self.box = ko.observable(b);
self.val = ko.observable(v);
self.txt = ko.computed(function () {
if (self.box()) {
return self.val() + ' checked';
}
else {
return self.val() + ' unchecked';
}
});
}
return DataModel;
}());
/*
* Array of initialized data.
*/
var boxVal = [
new DataModel(false, 'one'),
new DataModel(true, 'two'),
new DataModel(false, 'three')
];
/*
* View model.
*/
var ViewModel = (function () {
function ViewModel() {
var self = this;
self.boxVal = boxVal;
ko.applyBindings(self);
}
return ViewModel;
}());
var viewModel;
// When document fully loaded.
$(document).ready(function () {
// Create view model.
viewModel = new ViewModel();
});
//# sourceMappingURL=KoCheckboxIssue.js.map
</script>

</body>
</html>

I'll also attach the TypeScript used for this. It really fits well with Knockout. I've become a TypeScript evangelist...

Thanks again,

Bob Wirka

KoCheckboxIssue.ts

Bob Wirka

unread,
May 31, 2016, 10:34:00 AM5/31/16
to KnockoutJS
And, yes, what was really needed was to 'subscribe' to the check box observable, and to update the display from there. Duh.
Reply all
Reply to author
Forward
0 new messages