How can I detect when a div has lost focus?

Given the following markup, I want to determine when the editor has lost focus:

<div class="editor">
    <input type="text"/>
    <input type="text"/>
</div>
<div class="editor">
    <input type="text"/>
    <input type="text"/>
</div>
<button>GO</button>

      

EDIT: When the user enters tabs into the input elements, and since every editor div loses focus (which means they are laid out outside of the div), add a loading class to the div that has lost focus.

This bit of jquery is what I expected to work, but does nothing:

$(".editor")
.blur(function(){
    $(this).addClass("loading");
});

      

This seems to work until you add a console log and realize that it fires on every input focus.

$('div.editor input').focus( function() {
    $(this).parent()
        .addClass("focused")
        .focusout(function() {
            console.log('focusout');
            $(this).removeClass("focused")
                   .addClass("loading");        
        });
});

      

Here is the jsfiddle of my test case I am working on. I know I am missing something fundamental here. Can someone enlighten me?

EDIT: After some comments below, it almost works for me the way I want it. Now the problem is detecting the focus change somewhere outside the editor div. Here is my current implementation:

function loadData() {
    console.log('loading data for editor ' + $(this).attr('id'));
    var $editor = $(this).removeClass('loaded')
        .addClass('loading');

    $.post('/echo/json/', {
        delay: 2
    })
        .done(function () {
        $editor.removeClass('loading')
            .addClass('loaded');
    });
}

$('div.editor input').on('focusin', function () {
    console.log('focus changed');
    $editor = $(this).closest('.editor');
    console.log('current editor is ' + $editor.attr('id'));
    if (!$editor.hasClass('focused')) {
        console.log('switched editors');

        $('.editor.focused')
            .removeClass('focused')
            .each(loadData);

        $editor.addClass('focused');
    }
})

      

The use of classes for state is a bit more complicated. I've also added the next bit of complexity, which is to make an asynchronous call when the editor loses focus. Here is my jsfiddle of my current work.

+3


source to share


3 answers


If you want to treat the input and output of pairs of inputs as if they were combined into one control, you need to see if the element receiving focus is in the same control editor

. You can do this by delaying the check by one cycle using setTimeout

of 0 (which waits until all current tasks have completed).

$('div.editor input').focusout(function () {
    var $editor = $(this).closest('.editor');
    // wait for the new element to be focused
    setTimeout(function () {
        // See if the new focused element is in the editor
        if ($.contains($editor[0], document.activeElement)) {
            $editor.addClass("focused").removeClass("loading");
        }
        else
        {
            $editor.removeClass("focused").addClass("loading");
        }
    }, 1);
});

      

JSFiddle: http://jsfiddle.net/TrueBlueAussie/8s8ayv52/18/

To complete the puzzle (get the initial green state), you also need to catch the event as well focusin

and see if it comes from the same editor or not (keep the previous focused element in the global, etc.).



Side note: I recently had to write a jQuery plugin that did it all for groups of elements. It generates custom events groupfocus

and groupblur

to make it easier to work with the rest of the code.

Update 1: http://jsfiddle.net/TrueBlueAussie/0y2dvxpf/4/

Based on your new example, you can catch focus many times without damaging it, so you don't need to keep track of the previous focus. Using my previous setTimeout example, you are fixing the issue when clicking outside of a div.

$('div.editor input').focusin(function(){
    var $editor = $(this).closest('.editor');
    $editor.addClass("focused").removeClass("loading");

}).focusout(function () {
    var $editor = $(this).closest('.editor');
    // wait for the new element to be focused
    setTimeout(function () {
        // See if the new focused element is in the editor
        if (!$.contains($editor[0], document.activeElement)) {
            $editor.removeClass("focused").each(loadData);
        }
    }, 0);
});

      

+6


source


Here's what worked for me:

$(".editor").on("focusout", function() {
    var $this = $(this);
    setTimeout(function() {
        $this.toggleClass("loading", !($this.find(":focus").length));        
    }, 0);
});

      



Example:

http://jsfiddle.net/Meligy/Lxm6720k/

+1


source


I think you can do this. this is the example i did. Check it out: http://jsfiddle.net/igoralves1/j9soL21x/

$( "#divTest" ).focusout(function() {
alert("focusout");
});

      

-1


source







All Articles