views:

69

answers:

2

Hi all :)

Made this sweet little script to auto change fields after input. Works nicely in IE, Chrome and Safari, but not in FF or opera. JS code:

function fieldChange(id, e){            
            var keyID = (window.event) ? event.keyCode : e.keyCode;
            if (document.getElementById(id).value.length >= 2){
                if (keyID >= 48 && keyID <= 57 || keyID >= 96 && keyID <= 105){
                    switch(id){
                        case "textf1":
                            document.getElementById("textf2").focus();
                        break;                              
                        case "textf2":                              
                            document.getElementById("textf3").focus();
                        break;                      
                        case "textf3":
                            if (document.getElementById(id).value.length >= 4){
                                document.getElementById("nubPcode").focus();
                            }
                        break;                      
                    }
                }
            }

HTML:

                            <div class="privateOrderSchema">
                                <input type="text" id="textf1" name="textf1" maxlength="2" size="4" onKeyUp="fieldChange('textf1')"/>-
                                <input type="text" id="textf2" name="textf2" maxlength="2" size="4" onKeyUp="fieldChange('textf2')" />-
                                <input type="text" id="textf3" name="textf3" maxlength="4" size="5" onKeyUp="fieldChange('textf3')" />
                            </div>
                            <div class="privateOrderSchema">
                                <input type="text" id="nubPcode" name="nubPcode" size="4" maxlength="4" />
                                <br />
                            </div>

Does anybody know how to send the "e" var in this scenario?

Tnx all :D ur gr8!

A: 
onKeyUp="fieldChange('textf1')"

isn't passing the event object in the arguments. Instead:

onkeyup="fieldChange('textf1', event)"

This works both in IE (because event refers to the global variable window.event), and other browsers (because event refers to the single local argument of the function you are creating with the on... event handler attribute).

You can now drop the if (window.event) code from the fieldChange function, because the event will always be passed in. In places where you do need the event, it's better to sniff for the argument first before falling back to the IE version. Typically like:

function somethingHandler(event) {
    event= event || window.event;
    ...
}

Another thing you can do to clean up the markup is use this in the event handler:

onkeyup="fieldChange(this, event)"

now fieldChange don't have to look up the right element by id, since you already have a reference to it.

Better still, lose the event handler attribute and bind more unobtrusively. You can use the maxLength property too, instead of building in the length logic about exactly when the refocus occurs. eg.:

<input type="text" name="textf1" maxlength="2" class="movetonext" />
<input type="text" name="textf2" maxlength="2" class="movetonext" />
<input type="text" name="textf3" maxlength="4" class="movetonext" />

<script type="text/javascript">
    var elements= document.getElementById('myform').elements;
    for (var i= elements.length; i-->0;)
        if (elements[i].className==='movetonext')
            elements[i].onkeyup= checkMoveToNext;

    function checkMoveToNext() {
        if (this.value.length>=this.maxLength) {
            var elements= this.form.elements;
            var ix= List_indexOf(elements, this);
            ix= (ix+1)%elements.length;
            elements[ix].focus();
        }
    }

    function List_indexOf(list, item) {
        for (var i= 0, n= list.length; i<n; i++)
            if (list[i]===item)
                return i;
        return -1;
    }
</script>
bobince
Thanx, that solved it! Didn't know how to send the event, when added it worked nicely in ff aswell! Thanx! Nice additions aswell, going to study them when I get home from work ;)
s4v10r
@s4v10r As home go for Jquery... First do it and then work on the things again.. u can write much better code using Jquery.. with no cross browser issues...
piemesons
Dear Lord. The zealotry never ceases.
bobince
A: 

Something like the below would work, I think. It still does attach handler via the elements' attributes, which is unwanted, really. They should rather be attached via javascript.

In this attempt, you send the event, the this and an optional element id to the fieldChange function. It is pretty well commented down there, but in brief, it does this:

On keyup, check the length of the element's current value. If it is equal (or greater) in length to what is set in the maxlength, do some magic (if it is even longer, truncate the value to maxlength). In this keyup checking, don't do anything for keycodes 9 and 16 (this allows tabbing and shift-tabbing into a "full" input element).
The "magic" is jumping to the next element. That would be either the next element in the form or the element with the id that was optionally sent (explicitNextId).

It is now 16 lines of js, not counting the comments. HTH.

<body>
    <form action="#">
        <div class="privateOrderSchema">
            <input type="text" id="textf1" name="textf1" maxlength="2" size="4" onKeyUp="fieldChange(event, this)"/>-
            <input type="text" id="textf2" name="textf2" maxlength="2" size="4" onKeyUp="fieldChange(event, this)" />-
            <input type="text" id="textf3" name="textf3" maxlength="4" size="5" onKeyUp="fieldChange(event, this, 'nubPcode')" />
        </div>
        <div class="privateOrderSchema">
            <input type="text" id="nubPcode" name="nubPcode" size="4" maxlength="4" />
        </div>
    </form>

    <script type="text/javascript">
    function fieldChange(event, elem, explicitNextId) {
        // Obtain useable event
        event = window.event ? window.event : event;            
        var keyCode = event.keyCode, len = elem.value.length;
        // tab, shift (catches shift/tab) or small length, do nothing:
        if (keyCode===9 || keyCode===16 || len < elem.maxLength) {return;}
        // truncate value if exceding limit
        if (len>elem.maxLength) {elem.value=elem.value.substr(0, len-1);}
        // Get the next input to jump to (either from the id explicitly sent, or next in form)
        var next = getNextElement(elem, explicitNextId);
        // If one was found, focus it
        if (next) {next.focus();}
    }
    function getNextElement(elem, explicitNextId) {
        // From explicit id
        if (typeof explicitNextId!=='undefined') {return document.getElementById(explicitNextId);}
        // Get next in form
        var inputs = elem.form.elements;
        for (var idx=0, len=inputs.length-1, candidate; idx<len; ++idx) {
            candidate = inputs.item(idx);
            if (candidate===elem) {return inputs.item(idx+1);}
        }
    }
    </script>
</body>

After the helpful comment by bobince below, I changed some indexOf and Array/slice stuff in the getNextElement function to something that should work in IE too.

npup
thanx guys, ur gr8!
s4v10r
It's not normally kosher to call a method like `Array.slice` on potentially-host-objects like `HTMLCollection`. In any case, ECMAScript does not define a constructor-property `Array.slice`; that's Mozilla-only. Similarly, `Array#indexOf` is a Fifth Edition feature that is not available in IE.
bobince
@bobince Oh using indexOf on the array was an oversight, sorry. Fixed what concerned your about array and added some small tab-check too. Thanks for the pointer.
npup