3

I've seen similar topics posted on SO but mine is slightly different. I'm trying to keep my parent DIV (and children) in focus until I focus out of the div, and it seems surprisingly hard to accomplish.

This solution I thought would work but it looks to only applies to sibling elements and not the actual div itself.

Here's a demo of what I'm trying to do http://jsfiddle.net/nosfan1019/9Eg3k/3/. I need it so you can click on the gray portion and not have it disappear.

Community
  • 1
  • 1
Ryan Grush
  • 2,076
  • 3
  • 37
  • 64
  • I have a feeling you're looking for some combination of `click` and `mouseenter/leave` on the parent `div`, and that it could be simpler than that too. Have you tried just a `click` handler on the parent `div`? – Jared Farrish Jul 11 '12 at 01:55
  • @JaredFarrish I think I tried it at some point. I'll give it another shot though and let you know. – Ryan Grush Jul 11 '12 at 01:58
  • @Jeemusu a little too much lag :( – Ryan Grush Jul 11 '12 at 02:03
  • Please expand your explanation of exactly what you're trying to accomplish. You set the container style on focus enter/leave. A DIV cannot get focus as an INPUT element can. What are the rules you want to apply to add or remove the background color from the container? – Jim H. Jul 11 '12 at 02:21
  • @JimH. see the accepted answer – Ryan Grush Jul 11 '12 at 02:30
  • 1
    I had to fork it because of a problem jsFiddle was having updating the code. Here is what I have (not quite sure I got all the bugs out yet): http://jsfiddle.net/userdude/34HLU/ (I also wonder if some of it is necessary, so I'm checking that right now.) – Jared Farrish Jul 11 '12 at 03:17
  • 1
    One actual side effect that doesn't have a "clean" solution is that if you click on an `input`, then on the `div` parent, then somewhere not inside another `input`, the highlight stays. The only way I can see to do that is monitor `click` on a `parent` to the `div`s, ie, `$(document.body).on('click', $divs.find('input'), off)` in this case. Seems messy, a la `$.live()`. But `div` doesn't have a `blur` effect. Maybe on `$.mouseleave()` if `input` isn't focused? That seems like a problem though. And for some reason `$target.find('input').focus()` isn't firing, which is the obvious solution. – Jared Farrish Jul 11 '12 at 03:23
  • Who knew this would require such a workaround, jeez lol. On one hand its a lot longer than @A.M.K's solution but it does make a bit more sense than the 'tabindex' magic. I'll try cleaning up the code and see if I can shorten it up some. – Ryan Grush Jul 11 '12 at 03:34
  • There were some approaches that were dead-ends in that last code (almost all of the `e.stopPropagation()` and the `$(this).focus()`. This is more or less the least amount of code, seems to have the same effect: http://jsfiddle.net/userdude/34HLU/1/ Note, it still doesn't handle the double-off click preceded by the `.on` element click. – Jared Farrish Jul 11 '12 at 03:38
  • I'm not seeing the double-off problem for some reason. – Ryan Grush Jul 11 '12 at 03:47
  • It's there; if it doesn't bother you, that's fine. It just requires the `input blur()` to run explicitly, or another `input focus()`, to "dehighlight" a delegated click on a parent `div`. – Jared Farrish Jul 11 '12 at 03:52
  • Thanks for pointing it out. It might pop up somewhere down the line. – Ryan Grush Jul 11 '12 at 04:04

2 Answers2

3

Okay, I think that this is what you want:

Demo: http://jsfiddle.net/SO_AMK/GNfzw/

HTML:

<div>
    <input type='text'>
    <span></span>
</div>

<div>
    <input type='text'>
    <span></span>
</div>

<div>
    <input type='text'>
    <span></span>
</div>

CSS:

div {
    margin: 20px;
    padding: 10px;
    outline: 0;
}

jQuery:

$(function() {
    $('div input').parent().attr("tabindex",-1).focus( function() {
        $(this).css('background','#eee');
        $(this).find('span').text(' triggered');

        $(this).focusout(function() {
            $(this).children('span').empty();
            $(this).css('background','white');

        });            

   });
    $('div input').focus( function() {
        $(this).parent().css('background','#eee');
        $(this).siblings('span').text(' triggered');

        $(this).parent().focusout(function() {
            $(this).children('span').empty();
            $(this).css('background','white');

        });            

   });

});

It could probably be more efficient but it seems to work.

A.M.K
  • 16,727
  • 4
  • 32
  • 64
  • Hallelujah!! This is the longest I've banged my head against the wall in a while. I came across another posting that mentioned the "tabindex", what exactly is that doing? – Ryan Grush Jul 11 '12 at 02:29
  • To be honest, I'm not entirely sure how. – A.M.K Jul 11 '12 at 02:34
  • Oh, the `outline: 0;` is for chrome, it removes a yellow outline from the div when selected. – A.M.K Jul 11 '12 at 02:36
  • @RyanGrush - `tabindex` handles the `TAB` key order. – Jared Farrish Jul 11 '12 at 02:41
  • Yes, but that doesn't answer why it can make a `DIV` behave like an `INPUT` focus-wise – A.M.K Jul 11 '12 at 02:45
  • @JaredFarrish I know thats typically why its used, it just seems like it has a odd role in this solution. – Ryan Grush Jul 11 '12 at 02:47
  • @RyanGrush - I think it's just one of those "works" type of solutions. I've got one that doesn't toggle that and uses what I suggested above; are you still interested in seeing that approach? – Jared Farrish Jul 11 '12 at 03:04
  • @JaredFarrish I agree, its seems like I've come across several solutions that just work for some reason. Never would I ever thought to invoke the 'tabindex' for this ... Yea I would love to see another approach! – Ryan Grush Jul 11 '12 at 03:10
  • @RyanGrush - I know why this works with `tabindex`. You make it "focusable" with `tabindex`, but a `-1` value puts it out of the tab order (I think). Mainly, though, this just gives the `div`s the ability to accept `focus`, which makes sense with the `contenteditable` attribute for instance. This answer makes sense; I'd stick with this. – Jared Farrish Jul 11 '12 at 04:00
  • @RyanGrush - In fact, this literally helps me solve the problem I was complaining about in my approach: http://jsfiddle.net/userdude/34HLU/2/ (Which now that I notice does actually refocus to the `input`, whereas this answer doesn't, not sure if you want that or not.) – Jared Farrish Jul 11 '12 at 04:03
  • @JaredFarrish Yeah that was my more-or-less my suspicion. Its just odd thats seems to be the only shortcut to get the div to accept the focus. Thanks for your help! – Ryan Grush Jul 11 '12 at 04:06
  • @RyanGrush - The only reason I have to do it in mine is to fire the `blur()` correctly, which otherwise adds some cruft to accomplish. I'll add what I came up with as another answer, but I don't see what's wrong with this here. The two could be combined as well, I imagine. The only difference is mine refocuses, but this could too. – Jared Farrish Jul 11 '12 at 04:08
  • @JaredFarrish You both are on another skill level than I ;) Either way I think it would benefit the community to have a tight solution for this. – Ryan Grush Jul 11 '12 at 04:13
1

This is a bit of a more literal approach than the other answer, but for completeness seems relevant as it does one more thing: Autofocus back to the input. It could be useful, although the other answer is probably easy enough.

$(function() {
    var $divs = $('div'),
        $entered = null;

    var on = function() {
        var $target = $(this);

        _off();

        $entered = $target.parent().addClass('on');
        $target.siblings('span').text(' triggered');
    };

    var focus = function(){
        $(this).find('input').focus();
    };

    var off = function() {
        if ($entered !== null && $(this).parent().is($entered)) {
            return;
        }

        _off();
    };

    var _off = function(){
        $divs.removeClass('on').children('span').text('');
    };

    var entered = function(e){
        if (e.type == 'mouseenter') {
            $entered = $(this);
        } else {
            $entered = null;
        }
    };

    $divs.find('input').focus(on).blur(off);

    $divs
        .attr('tabindex', -1)
        .bind('mouseenter mouseleave', entered)
        .bind('focus', focus);
});

http://jsfiddle.net/userdude/34HLU/2/

Jared Farrish
  • 48,585
  • 17
  • 95
  • 104