Since you tagged this as a jQuery question as well, here's a simple (well, fairly simple) jQuery solution:
$('#text_statute_section').on('keypress', function(event) {
if(null !== String.fromCharCode(event.which).match(/[a-z]/g)) {
event.preventDefault();
$(this).val($(this).val() + String.fromCharCode(event.which).toUpperCase());
}
});
Using keypress prevents the "bounce" effect that keyup has (keydown also does, but event.which doesn't distinguish directly between upper and lower case here--shift key check is messy owing to caps lock). Also, this operates on the input character, converts it to uppercase, and then appends it to the existing value, rather than first appending and then converting the whole thing to uppercase as most of the other solutions I've seen do. Finally, it actually converts the character rather than applying a formatting style to it as CSS does. All this gives better control, especially in situations where some characters need to be forced to uppercase and some not, such as in serial numbers or the like.
EDIT: (four years later)!
I've never been happy with how jQuery/javascript handles changing keys to uppercase as they are typed in. I've been over all the suggestions in this post, and none of them (least of all mine) quite work flawlessly. This is irritating to me, as it was a simple matter in the old VB6 days to change the KeyAscii character that was passed to the KeyPress event. Anyway, quite by accident, I have found a sort of "black art" solution that does work flawlessly as far as I have tested it. Meaning it works in Chrome, it correctly handles any cursor position on the text, it (with some work) doesn't change the browser's focus behavior, and it reliably changes to uppercase without any sort of jittery showing of lowercase first. While the CSS solution also does all of this, as others have observed it has the drawback of having to programmatically force the underlying characters to uppercase when you need the actual string to work with, which can be a hassle to keep track of and therefore doesn't scale well. So, I thought I might write this up, in case someone finds it useful.
This solution does depend on Josh Bush's little (180 lines of code, for those worried about dependency bloat) Masked Input Plugin from digitalbush, which is rock solid and does what it does very well. If you change event.which
to another value, and call the mask()
method afterwards (specify the keypress handler first and the mask second in your code) the change will persist.
Here's a bit of code:
$.mask.definitions['b'] = '[A-Z, ]';
$('#txtMyInput').on('keypress', function(e) {
e.which = String.fromCharCode(e.which).toUpperCase().charCodeAt(0);
})
.mask('b?bbbbbbbbbbbbbbbbbbb', { placeholder: '' })
Mask doesn't support very many mask types natively: literals, alpha, numeric and alphanumeric are it. If you want punctuation or whatever you have to roll your own using regex. (If you do this, you'll need to keep in mind that the same regex match is applied to each character one at a time, without consideration of the other characters, so you can't do anything fancy). In my particular case, I needed all caps, plus spaces and commas. The ?
in the mask string means the following characters are optional, so this one gives me up to 20 characters. Since I didn't need any mask to show, I used an empty string for a placeholder.
That all works perfectly, except for the one small problem: if you want to keep the way the browser selects the text when tabbing into the field, you have to do extra work. I wound up having to hack the mask code to get what I wanted.
I first tried simply selecting the text in a focus event handler, which normally works when I call focus()
from a keydown handler. It didn't work here; the cursor just got set to the end of the text as it would on a mouse click there. I tried changing the placeholder to a space. This resulted in padding the text with enough spaces to fill up the limit specified, and selecting the whole thing.
I tried some of the techniques here, but the best of them (i.e. the one that actually worked in this case) still doesn't apply the highlight until key up, which means there's a lag in when it happens, and it doesn't happen at all if you hold the key down till it repeats and happen to let go when the focus is in the box.
So I dug into the mask code. As it turns out, the plugin also has a focus event handler that it uses to set up the mask indicator (say, (___) ___-___-____
for a phone) in the box when you focus on it. This is the behavior you want most of the time, but not here, because it replaces the selected text with the selected text concatenated to the part of the mask indicator that hasn't been filled yet. When you don't have a mask indicator, this has the effect of deselecting the text in the box just as would happen if you programmatically assigned the text value of the box.
I decided to hack the mask code a bit. I first tried commenting out the entire focus event handler, which had the effect of not showing the input mask on other fields where I wanted it. So, I found a less invasive alternative. I changed this (currently jquery.maskedinput.js, line 164):
}).on("focus.mask", function() {
if (!input.prop("readonly") {
// etc.
to this:
}).on("focus.mask", function() {
if (!input.prop("readonly") && settings.placeholder.length > 0) {
This bypasses setting up the mask indicator if you have set your placeholder to a blank string, which allows the browser's native focus behavior to take place.
One more thing: if you are using the focus()
method to focus on the text box (for example, to rescue the data entry user from the browser's tendency to wander to parts unknown upon use of the tab key), you'll have to call the select()
method in the focus event handler to properly highlight the text (keybdFocus
is a flag I set when I call the focus()
event from a keydown
handler, so as to distinguish from a mouse-generated focus):
$('#txtMyInput').on('keypress', function(e) {
e.which = String.fromCharCode(e.which).toUpperCase().charCodeAt(0);
})
.mask('b?bbbbbbbbbbbbbbbbbbb', { placeholder: '' })
.focus(function() {
if (kybdFocus) {
kybdFocus = false;
$(this).select();
}
});
Summarizing the steps:
- Download Josh Bush's Masked Edit Plugin.
- Change the line of code in the plugin's focus handler.
- Set up a mask definition (if needed) to handle the characters you want.
- In your keypress event handler, use your favorite technique to change e.which to its uppercase equivalent. (Important: the call to the handler must precede the call to the
mask()
method in your code. The mask evaluates e.which to determine whether the candidate character fits the mask, and apparently the handler and the mask code are fired in the order in which they are specified.)
- Set the placeholder value to
''
when you call the mask()
method.
- If you hit the input box with a focus, call the
select()
method in your focus event handler.
Of course, if you just want to force characters to uppercase in the context of a typical masked edit box, you can omit steps 2 and 4. That's how I fell into this in the first place.