Dan Lugg
Dan Lugg

Reputation: 20592

jQuery events; prevent "siblings" from triggering each others events

Using jQuery 1.6.1, given I have the following HTML:

<div class="control">
    <label>My Control</label>
    <input type="text" />
    <input type="text" />
</div>

When an <input> in <div class="control"> (hereafter only control) is focused, the <label> (with position: relative;) animates:

$('.control :input').bind('focus', function(e){
    $(this).prevAll('label').animate({
        'left': '-50px'
    }, 250);
});

And when blurred, the <label> returns:

.bind('blur', function(e){
    $(this).prevAll('label').animate({
        'left': '0px'
    }, 250);
});

However, if one of the <input> elements gains focus, and then blurs as focus is switched to another <input> within the same control (via Tab or mouse click) the events of course still fire, and the <label> animates back and forth.

How can I force the blur event to trigger only when focus is lost from all inputs within a given control?

Upvotes: 2

Views: 1127

Answers (5)

Ruslan Polutsygan
Ruslan Polutsygan

Reputation: 4461

In blur callback you can detect if any input element is focused now using this $("input:focus").length. If length>0 than do not animation

Update

What about this code?

    var control;
    var inTheSameControl=false;
    $('.control :input').bind('focus', function(e){
        if(control)
        {
            if(control.find(this).length>0)
                inTheSameControl=true;
            else
                inTheSameControl=false;
        }
        control=$(this).parent();
        if(!inTheSameControl)
        {
            console.log('focus');
        }
    });
    $('.control :input').bind('blur', function(e){
        if(!inTheSameControl)
        {
            console.log('blur');
        }
    });

It works with multiple div.control When you are switching focus to the input in another .contor, text 'focus' logs into console, if you are staying in the same .control - doesn't. Instead of console.log(...) you may write what you want. I haven't written your code(animation) because it is not the subject.

I hope it will be helpfull.

Upvotes: 1

Chandu
Chandu

Reputation: 82893

Edit: Updated the answer based on more inputs provided by the OP.

If a slight delay of one second to hide the label is fine then you can use setTimeout/clearTimeout combination.. Something like:

<div class="control">
    <label>My Control</label>
    <input type="text" />
    <input type="text" />
    <input type="text" />
</div>
<div class="control">
    <label>My Control</label>
    <input type="text" />
    <input type="text" />
    <input type="text" />
</div>

<div class="control">
    <label>My Control</label>
    <input type="text" />
    <input type="text" />
    <input type="text" />
</div>

<div class="control">
    <label>My Control</label>
    <input type="text" />
    <input type="text" />
    <input type="text" />
</div>

    <script type="text/javascript"> 
        var timeoutIds = [];
            $('.control').each(function(index, el){
                $(':input', el).bind('focus', function(e){     
                        clearTimeout(timeoutIds[index]);
                        $(this).prevAll('label').animate({        
                                'left': '-50px'     
                        }); 
                });

                $(':input', el).bind('blur', function(e){     
                        var that = this;
                        timeoutIds[index] = setTimeout(function(){
                            $(that).prevAll('label').animate({        
                                    'left': '0px' 
                            }); 
                    }, 500);
                });
            });
    </script>

Working example: http://jsfiddle.net/Tn9sV/2/

Upvotes: 1

rkw
rkw

Reputation: 7297

Two options I can think of:

  • Option 1 (using current scheme):

    • blur: .delay your animation by a fraction of a second

    • focus: .stop your existing animation

  • Option 2 (change blur item):

    • chage the blur item to be on your div instead of the label

Upvotes: 0

citizen conn
citizen conn

Reputation: 15390

I have achieved something similar in the past by binding a new focus to the document or to the form instead and having that trigger the label to come back, instead of binding a blur to the inputs.

Upvotes: 1

Alex Mcp
Alex Mcp

Reputation: 19315

In your blur callback I would look at something like the :focus selector that was introduced in 1.6:

Using jQuery to test if an input has focus

If $('.control :focus).length > 0 then return the function to stop it from running.

Upvotes: 1

Related Questions