kevmor
kevmor

Reputation: 172

How to traverse through other parents with jQuery?

I have many forms on a website and I'd like to use jQuery to transverse so that when you press PgUp / PgDn it will go to the next <textarea> field. I got it working when the <textarea>'s were siblings, but if they're in a separate form (with different parents) I can't figure it out.

The HTML is like:

<form action="#" method="post">
    <textarea id="numOne" name="numOne" class="num" ></textarea>
</form>
<form action="#" method="post">
    <textarea id="numtwo" name="numtwo" class="num" ></textarea>    
</form>
<form action="#" method="post">
    <textarea id="numthree" name="numthree" class="num" ></textarea>    
</form>

This worked when they were siblings:

$('.num').keydown(function (e) {

    if (e.which == 34) {

        $(this).next().focus();

        e.preventDefault();
        return false;
    } 
    if (e.which == 33) {
        $(this).prev().focus();

        e.preventDefault();
        return false;
    }


});

Upvotes: 4

Views: 82

Answers (3)

Roko C. Buljan
Roko C. Buljan

Reputation: 206121

LIVE DEMO

$('.num').keydown(function (e) {

    if (e.which == 34) {
        $(this).closest('form').next('form').find('.num').focus();
        return false;
    } 
    if (e.which == 33) {
        $(this).closest('form').prev('form').find('.num').focus();
        return false;
    }

});

As you can see I used .closest('form') it will allow you one day to use your textarea inside a fieldset without taking care of the jQuery, cause it'll always traverse the DOM the right way.

Another nice way: DEMO

$('.num').keydown(function (e) {
    var k = e.which;  
    if ( k==34 || k==33 ){
      $(this).closest('form')[k==34?'next':'prev']('form').find('.num').focus();
      e.preventDefault();
    }    
});

Another nice DEMO

var $num = $('.num').keydown(function(e) {
    var k=e.which, c=$num.index(this);  
    if(k==34||k==33) $num[k==34?++c:--c].focus();
});

Let's go through the last one:

var $num = $('.num')              // Create a jQuery Array collection
                                  // of all the .num in the DOM.
    .keydown(function(e) {        // On keydown pass the (e)vent.
        var k=e.which,            // Var k is now the "which keyCode"
            c=$num.index(this);   // Var c will be the index of the clicked
                                  // element taken from the collection.
        if(k==34||k==33)          // Only IF pgUp/pgDn
        $num[k==34?++c:--c]       // increment or decrement c and get that el.
                                  // out of the array ( e.g: $num[1] )
        .focus();                 // and set focus to it.
}); 

Upvotes: 1

adeneo
adeneo

Reputation: 318212

You should use the collection of elements to get the next and previous elements, that way the DOM structure doesn't matter and you can nest the elements any way you like :

var elems = $('.num');

elems.on('keydown', function (e) {
    var n = e.which === 34 ? 1 : e.which === 33 ? -1 : 0,
        next = elems.eq(elems.index(this) + (n));

    if (n) {
        e.preventDefault();
        next.length ? next.focus() : elems.first().focus();
    }
});

FIDDLE

Upvotes: 2

Brigand
Brigand

Reputation: 86240

You can use .index and .eq to perform next/prev searches on a selector. In this case, we look at all textareas on the page, and figure out which one we're currently in, say the 22nd textarea. Then we either select the 21st or 23rd textarea, and focus it.

This is more robust than other solutions which rely on the DOM structure. This simply relies on the DOM order. It can further be refined by changing $('textarea') to $('#scope textarea') where scope is the highest parent you wish to look inside.

If your HTML will be changing (new or removed textareas) then don't cache the result as I did. However, it improves performance if your HTML won't be changing in this area.

var $textareas = $('textarea');

$('.num').keydown(function (e) {
    if (e.which == 34) {

        var index = $textareas.index(this)
        $textareas.eq(index + 1).focus();

        e.preventDefault();
        return false;
    }

    if (e.which == 33) {
        var index = $textareas.index(this)
        $textareas.eq(index - 1).focus();

        e.preventDefault();
        return false;
    }
});

fiddle

Upvotes: 1

Related Questions