36

The HTML on the page has 20 <input> fields each named and given ID's in increasing order from 1 to 20.

If the variable id is set to the next sequential id (id + 1), this function will cause focus to apply to that field. However, when clicking outside of the current input field, the last one input field will not regain focus if the number entered is greater than 10, but an alert will be displayed.

$(":input").focusout(function(){
    var input = $(this).val();
    var id    = $(this).attr('id');
    if(input > 10){ 
        alert('You must enter a number between 0 and 10 '+id);
        $("#"+id).select();
    }
});

How can the last input field be set to regain focus?

Tui Popenoe
  • 2,098
  • 2
  • 23
  • 44
Somk
  • 11,869
  • 32
  • 97
  • 143

5 Answers5

41

Try replacing:

$("#"+id).select();

With:

$(this).focus();

In this case, $("#"+id) and $(this) are the same element, and I'm assuming you want to focus the element when there is an error.

Aside: I don't believe that id or name values can legally start with a number, you may want to prefix them with something like option1, option2, etc. It might work, but it might also cause issues later that are difficult to debug. Best to err on the side of caution and best practices.

What are valid values for the id attribute in HTML?

Edit: After failing to get focus() to work, I tried with setTimeout and was able to make it happen. I'm not sure why, or if this is really necessary, but it seems to work.

$(":input").focusout(function(){
    var $this = $(this),
        input = $this.val();

    if (input > 10){
        alert('You must enter a number between 0 and 10');
        setTimeout(function(){
        $this.focus();
        }, 1); 
    }
}); 

I'd love to hear if there is a better way to do this or an explanation. I suspect that the blur and focus events are not fired in an order that makes the previous method possible?

Demo: http://jsfiddle.net/zRWV4/1/

As mentioned in the comments, you should eventually make sure the value is an integer with parseInt or similar (you seem to already be aware of this).

Community
  • 1
  • 1
Wesley Murch
  • 101,186
  • 37
  • 194
  • 228
  • I've tried this. It seems to have the same problem. Cheers though – Somk Aug 12 '11 at 20:40
  • Yeah, I can't seem to get `focus()` to work even outside the context of the function for some reason (at least on jsfiddle). I hope you find the solution, I'm at a loss for an explanation. – Wesley Murch Aug 12 '11 at 21:00
  • Thank you for your mentioning best practices too. It doesn't seem to have made it work, but thanks again – Somk Aug 12 '11 at 21:04
  • 1
    Thanks it works perfectly. You have put alot of effort into this response. I am going to accept this answer. As it does resolve my issue. But like you I am intrigued to see if there is a better way to accomplish this. Thanks for all the help. – Somk Aug 12 '11 at 21:59
  • Yeah Max, I'm at a loss here.. it seems only FF5 needed the `setTimeout` call. Well, GL and see related new question: http://stackoverflow.com/questions/7046798/jquery-focus-fails-on-firefox – Wesley Murch Aug 12 '11 at 22:01
  • Cheers Wesley, Thanks for the link. I will be keeping an ear to the ground about this. Once again thanks for the solution. – Somk Aug 12 '11 at 22:06
  • 1
    When you apply setTimeout with a delay of 0 seconds, you can be sure that the code you put in the delayed function is executed after the main processing is finished. I guess the behaviour described in the question happens because the browser triggers focus on the next element after $this.focus() is ran. If you implement a focus-event writing something to console.log you'll see that two focus events are triggered when you leave an invalid field. – Jørgen Aug 12 '11 at 22:11
2

replace

$("#"+id).select();

by

$("#"+id).focus();

or even by

$(this).focus();
akjoshi
  • 15,374
  • 13
  • 103
  • 121
pixeline
  • 17,669
  • 12
  • 84
  • 109
0

(Try to use .blur() instead of .focusout(). But that probably won't help)

Try to remove the alert() for a while - it sometimes can make problems with focus...

Tomas
  • 57,621
  • 49
  • 238
  • 373
  • it is firing already so I don't think this is the issue. I did change the script and try this though anyway. Thank you – Somk Aug 12 '11 at 20:45
  • @Max: ... I was afraid so... so try to remove the `alert()` for a while - it sometimes can make problems with focus... – Tomas Aug 12 '11 at 21:07
  • Removed the alert, didn't seem to make any difference. I was able to click into another input and type away. – Somk Aug 12 '11 at 21:10
0

You should parse the text inside the input to compare it with a number. var input = parseInt($(this).val()); '

   $(":input").blur(function(){
        var input = parseInt($(this).val());
        var id    = $(this).attr('id');
        if(input > 10){ 
            alert('You must enter a number between 0 and 10 '+id);
            $("#"+id).select();
        }
    });
Mohsen
  • 64,437
  • 34
  • 159
  • 186
  • Cheers for the advice. I tried your version to no avail. I will probably implement the parseInt though once I find out what is not allowing the focus to fire correctly. Thanks – Somk Aug 12 '11 at 21:12
0

jsFiddle Example

This is my code, I'll explain what I changed:

$('input[id^="input"]').focusout(function(){
    var selected = parseInt($(this).val(), 10);
    if (selected <= 10) {
        $("#input-"+selected).focus();
    }
    else {
        alert('Invalid Argument! 1-10 only!');
        $(this).focus();
    }
});
  1. I use focus() instead of select() which won't work.
  2. You confused id with select which caused you to always try and select $("#input-IDOFSELECTIONINPUT") instead of $("#input-IDOFWANTEDINPUT")
  3. In your code, although an alert would have been thrown, the rest of the code would have continued normally. It won't in my code.
  4. You've put your desired result ($("#"+id).select();) in the undesired condition (input > 10), which practically never gave it a chance.
  5. Last but not least, I gave the inputs a better (and valid) id. IDs must not start with a number.
Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308