How To Change Text For Selected Fields To Uppercase Using KnockoutJS?
This is a custom binding I wrote that makes sure both the input field and the observable is upper case. It should work just like a textInput binding.
ko.bindingHandlers.textInputUpperCase = {
init: (element, valueAccessor) => {
const observable = valueAccessor();
let preventDoubleUpdate = false;
function update(newValue) {
if (preventDoubleUpdate) {
preventDoubleUpdate = false;
} else {
switch(typeof newValue) {
//Undefined value will be displayed as empty in the input field.
case 'undefined':
element.value = '';
break;
//String value will be converted to upper case.
case 'string':
const upperCase = newValue.toLocaleUpperCase();
//Check if input field matches the observable. If not the change was made directly to the observable.
const match = element.value.toLocaleUpperCase() === upperCase;
//Remember the cursor position.
const selectionStart = element.selectionStart;
const selectionEnd = element.selectionEnd;
//Update the input text (will move the cursor to the end of the text).
element.value = upperCase;
//Move the cursor to it's original position if the change came from the input field.
if (match) {
element.selectionStart = selectionStart;
element.selectionEnd = selectionEnd;
}
//Update the observable if necessary and make sure it won't do a double update.
if (newValue !== upperCase) {
preventDoubleUpdate = true;
observable(upperCase);
}
break;
default:
element.value = newValue;
}
}
}
//Run the update function each time the observable has been changed
observable.subscribe(update);
//Initiate the observable and input
update(observable());
//Update the observable on changes of the text in the input field
element.addEventListener('input', event => {
observable(event.target.value);
});
}
};
A small caveat. If you write to the observable it will notify other subscribers twice. First when you write to it and then when it gets upper cased.
You could extend your observables -
<input data-bind="value: colorName, valueUpdate:'afterkeydown'" />
ko.extenders.uppercase = function(target, option) {
target.subscribe(function(newValue) {
target(newValue.toUpperCase());
});
return target;
};
var colorName = ko.observable().extend({ uppercase: true });
fiddle example - http://jsfiddle.net/kbFwK/
Basically whenever the value changes it will convert the value of the observable to upper case.
The disadvantage here is that it actually changes the value and would store it that way as well. You could always tack on a computed property onto the observable just for display purposes as well. You could do that using a ko.computed, a custom binding handler (since it is just for presentation), or something similar. If that is more of what you are looking for let me know with a comment.
Edit
Updated with afterkeydown - http://jsfiddle.net/kbFwK/2/