Skip to content

Commit

Permalink
Work around IE < 8 issue - it insists that OPTION nodes must have val…
Browse files Browse the repository at this point in the history
…ue attributes (even if they don't), so use marker text to identify when an option is associated with a DOM data value
  • Loading branch information
SteveSanderson committed Aug 16, 2010
1 parent 320e191 commit 1b39996
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 35 deletions.
19 changes: 12 additions & 7 deletions src/binding/defaultBindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,13 @@ ko.bindingHandlers.value = {
init: function (element, value, allBindings) {
var eventName = allBindings.valueUpdate || "change";
if (ko.isWriteableObservable(value))
ko.utils.registerEventHandler(element, eventName, function () { value(ko.selectExtensions.readValue(this)); });
ko.utils.registerEventHandler(element, eventName, function () {
value(ko.selectExtensions.readValue(this));
});
else if (allBindings._ko_property_writers && allBindings._ko_property_writers.value)
ko.utils.registerEventHandler(element, eventName, function () { allBindings._ko_property_writers.value(ko.selectExtensions.readValue(this)); });
ko.utils.registerEventHandler(element, eventName, function () {
allBindings._ko_property_writers.value(ko.selectExtensions.readValue(this));
});
},
update: function (element, value) {
var newValue = ko.utils.unwrapObservable(value);
Expand Down Expand Up @@ -96,17 +100,18 @@ ko.bindingHandlers.options = {
if (typeof value.length != "number")
value = [value];
if (allBindings.optionsCaption) {
var option = document.createElement("OPTION");
option.innerHTML = allBindings.optionsCaption;
element.appendChild(option);
var option = document.createElement("OPTION");
option.innerHTML = allBindings.optionsCaption;
ko.selectExtensions.writeValue(option, undefined);
element.appendChild(option);
}
for (var i = 0, j = value.length; i < j; i++) {
var option = document.createElement("OPTION");
var optionValue = typeof allBindings.optionsValue == "string" ? value[i][allBindings.optionsValue] : value[i];
if (typeof optionValue == 'object')
ko.utils.domData.set(option, ko.bindingHandlers.options.optionValueDomDataKey, optionValue);
ko.selectExtensions.writeValue(option, optionValue);
else
option.value = optionValue.toString();
option.value = optionValue.toString();
option.innerHTML = (typeof allBindings.optionsText == "string" ? value[i][allBindings.optionsText] : optionValue).toString();
element.appendChild(option);
}
Expand Down
59 changes: 31 additions & 28 deletions src/binding/selectExtensions.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
(function () {
// Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
// are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
// that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
ko.selectExtensions = {
readValue : function(element) {
if (element.tagName == 'OPTION') {
var valueAttributeValue = element.getAttribute("value");
if (valueAttributeValue !== null)
return valueAttributeValue;
return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
} else if (element.tagName == 'SELECT')
return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
else
return element.value;
},

writeValue: function(element, value) {
if (element.tagName == 'SELECT') {
for (var i = element.options.length - 1; i >= 0; i--) {
if (ko.selectExtensions.readValue(element.options[i]) == value) {
element.selectedIndex = i;
break;
}
}
} else
element.value = value;
}
};
// Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
// are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
// that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
ko.selectExtensions = {
readValue : function(element) {
if (element.tagName == 'OPTION') {
var valueAttributeValue = element.getAttribute("value");
if (valueAttributeValue !== ko.bindingHandlers.options.optionValueDomDataKey)
return valueAttributeValue;
return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
} else if (element.tagName == 'SELECT')
return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
else
return element.value;
},

writeValue: function(element, value) {
if (element.tagName == 'OPTION') {
ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
element.value = ko.bindingHandlers.options.optionValueDomDataKey;
} else if (element.tagName == 'SELECT') {
for (var i = element.options.length - 1; i >= 0; i--) {
if (ko.selectExtensions.readValue(element.options[i]) == value) {
element.selectedIndex = i;
break;
}
}
} else
element.value = value;
}
};
})();

0 comments on commit 1b39996

Please sign in to comment.