My application owners want select text fields to be uppercase as if the caps lock is on. I am using a KnockoutJS viewmodel with observables for these fields. Is there a way I can in effect convert any user entered text to upper case?
I put a input
event on the controls I wanted to change but found that although it works, the observables are not updated.
<input type="text" maxlength="80" data-bind="value: colorName, disable: $parent.isReadOnly, event: { 'input': toUpper }" />
toUpper: function (d, e) {
if (e.target) {
if (e.target.value) {
e.target.value = e.target.value.toUpperCase();
}
}
}
I have also been thinking of putting a ucase
CSS class on the controls I want to be upper case and then either on the client or server, saving those fields in upper case.
.ucase {
text-transform: uppercase;
}
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/
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.
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