0
\$\begingroup\$

I posted a question on Stack Overflow and got an answer that works but has a lot of duplicated code. In the future, the functionality may also require a third or more divs to be shown or hidden. The original script also came from a SO answer.

Can this code be refactored or improved to accommodate more than 2 inputs and hidden divs?

When the client focuses in a text field the associated div is shown or hidden on blur.

//BASED OFF SO SINGULAR EXAMPLE
//https://stackoverflow.com/questions/2426438/jquery-on-form-input-focus-show-div-hide-div-on-blur-with-a-caveat#answer-2427363
    
    
    
//CAN THESE TWO BE REFACTORED???
$('#search-markets').focus(function() {
    $('div.select-markets-filters').css('display', 'flex');
    $(document).bind('focusin.select-markets-filters click.select-markets-filters',function(e) {
        if ($(e.target).closest('.select-markets-filters, #search-markets').length) return;
        $(document).unbind('.select-markets-filters');
        $('div.select-markets-filters').slideUp(300);
    });
});
$('div.select-markets-filters').hide();

//CAN THESE TWO BE REFACTORED???
$('#search-symbols-instruments').focus(function() {
    $('div.select-symbols-instruments-filters').css('display', 'flex');
    $(document).bind('focusin.select-symbols-instruments-filters click.select-symbols-instruments-filters',function(e) {
        if ($(e.target).closest('.select-symbols-instruments-filters, #search-symbols-instruments').length) return;
        $(document).unbind('.select-symbols-instruments-filters');
        $('div.select-symbols-instruments-filters').slideUp(300);
    });
});
$('div.select-symbols-instruments-filters').hide();
#select-data-inputs {
    background-color: #000;
}

.select-filters {
    background-color: rgba(0, 0, 0, 0.8);
    border-top: 2px solid #fff;
    color: #fff;
}

#select-symbols {
    background-color: rgba(1, 56, 89, 0.85);
}

#select-markets {
    background-color: rgba(2, 104, 165, 0.85);
}

.filter-list li.list-inline-item {
    width: 48%;
    margin: 0;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">   

 <div class="container-fluid">
        <div class="row m-5 ">
            <div class="col-12 text-center">
                <h1>On form inputs focus, show div. hide div on blur for <span class="text-danger">multiple inputs</span> and hidden divs</h1>
                <p class="lead"><i><a href="https://stackoverflow.com/questions/2426438/jquery-on-form-input-focus-show-div-hide-div-on-blur-with-a-caveat" target="_blank">Based from SO sigular example</a></i></p>
            </div>
        </div>
        <div class="row">
            <div id="select-data-inputs" class="controls form-row p-3 w-100">
                <div class="col-4">
                    <input type="text" id="search-markets" class="input form-control" placeholder="Search Markets">
                </div>
                <div class="col-4 offset-1">
                    <input type="text" id="search-symbols-instruments" class="input form-control" placeholder="Search Symbols">
                </div>
            </div>
        </div>
        <div id="main-display">
            <div id="select-markets" class="row select-filters select-markets-filters p-4">
                <div class="select-heading col-12 pl-2">
                    <h6 class="small-sub-heading">Select markets</h6>
                </div>
                <div class="col-4 pt-2 select-filter-items">
                    <ul class="filter-list list-unstyled pl-2">
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="market-option-1" value="market-option-1">
                            <label class="form-check-label" for="market-option-1">Market Option 1</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="market-option-2" value="market-option-2">
                            <label class="form-check-label" for="market-option-2">Market Option 2</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="market-option-3" value="market-option-3">
                            <label class="form-check-label" for="market-option-3">Market-Option 3</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="market-option-4" value="market-option-4">
                            <label class="form-check-label" for="market-option-4">Market-Option 4</label>
                        </li>
                    </ul>
                </div>
            </div>
            <div id="select-symbols" class="row select-filters select-symbols-instruments-filters p-4">
                <div class="select-heading col-4 offset-5 pl-2">
                    <h6 class="small-sub-heading">Select symbols</h6>
                </div>
                <div class="col-4 offset-5 pt-2 select-filter-items">
                    <ul class="filter-list list-unstyled pl-2">
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="symbol-option-1" value="symbol-option-1">
                            <label class="form-check-label" for="symbol-option-1">Symbol Option 1</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="symbol-option-2" value="symbol-option-2">
                            <label class="form-check-label" for="symbol-option-2">Symbol Option 2</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="symbol-option-3" value="symbol-option-3">
                            <label class="form-check-label" for="symbol-option-3">Symbol Option 3</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="symbol-option-4" value="symbol-option-4">
                            <label class="form-check-label" for="symbol-option-4">Symbol Option 4</label>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.bundle.min.js" integrity="sha384-pjaaA8dDz/5BgdFUPX6M/9SUZv4d12SUPF0axWc+VRZkx5xU3daN+lYb49+Ax+Tl" crossorigin="anonymous"></script>
    

\$\endgroup\$
  • \$\begingroup\$ Have you tried anything yourself? It's very easy to post someone else's code here and expect an even better version in return, but do you understand how and why it's written the way it is? That's quite essential. \$\endgroup\$ – Mast Jan 26 at 6:25
  • \$\begingroup\$ Yes I have spent many hours researching the initial issue of showing the hidden div on focus in the text input but not hiding the div when focus is shifted (except the now displayed div). It was beyond my programming capability that was why I asked the question. \$\endgroup\$ – Kerry7777 Jan 26 at 7:11
  • \$\begingroup\$ @Kerry7777 did you post the question (with the unregistered account)? If so, you can request your account be merged with the unregistered account via the contact link in the lower left corner of the page \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Jan 26 at 7:42
4
\$\begingroup\$

The HTML and CSS are unchanged from your snippet (I did remove the preamble).

The appendTo line ensures the newly-visible div is always last on the list of divs, which fixes a quirk of the original where the animation would look different depending on whether the new came before or after the old.

The logic works like this:

  • add a focus handler to the input fields which derives the info-box classname from the field's id. This handler hides all other (.not(e)) info-boxes and makes the current one visible.
  • add a blur handler to those same fields, to hide on blur, unless it has the inuse class (see below)
  • add a focusin / mousedown handler to the info-box container and its children, which add the inuse class to the clicked/focused box, preventing the blur handler above from hiding them. The focusin and mousedown events happen before the blur event fires on the input field.
  • add a focus / click handler, as above, to remove the inuse class, which allows hiding. These come after the blur event, so they won't be hidden immediately -- only if you click or focus somewhere else later.

So when you click on a visible info-box, the sequence is:

  1. nohide() fires; box becomes inuse
  2. blurplus() fires; does nothing because inuse
  3. allowhide() fires; box retains focus but loses inuse class, making it eligible to future hiding

function focusplus() { 
    var e=$(`div.select-${ this.id.replace(/^search-/,'') }-filters`).first();
    if (!e.length) return;
    $('.row.select-filters:visible').not(e).slideUp(300);
    e.appendTo("#main-display").css('display', 'flex');
}

function blurplus() { 
    $('.row.select-filters:visible:not(.inuse)').slideUp(300);
}

function nohide(e) {      
   $(e.target).closest('.row').addClass('inuse');
}

function allowhide(e) { 
    $(e.target).closest('.row').removeClass('inuse');
}

$('.row.select-filters').hide()
$("#main-display")
    .on('focusin mousedown', '*', nohide)
    .on('click focus', '*', allowhide);

$('#search-markets, #search-symbols-instruments').focus(focusplus).blur(blurplus);
#select-data-inputs {
    background-color: #000;
}

.select-filters {
    background-color: rgba(0, 0, 0, 0.8);
    border-top: 2px solid #fff;
    color: #fff;
}

#select-symbols {
    background-color: rgba(1, 56, 89, 0.85);
}

#select-markets {
    background-color: rgba(2, 104, 165, 0.85);
}

.filter-list li.list-inline-item {
    width: 48%;
    margin: 0;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">   

 <div class="container-fluid">
        <div class="row">
            <div id="select-data-inputs" class="controls form-row p-3 w-100">
                <div class="col-4">
                    <input type="text" id="search-markets" class="input form-control" placeholder="Search Markets">
                </div>
                <div class="col-4 offset-1">
                    <input type="text" id="search-symbols-instruments" class="input form-control" placeholder="Search Symbols">
                </div>
            </div>
        </div>
        <div id="main-display">
            <div id="select-markets" class="row select-filters select-markets-filters p-4">
                <div class="select-heading col-12 pl-2">
                    <h6 class="small-sub-heading">Select markets</h6>
                </div>
                <div class="col-4 pt-2 select-filter-items">
                    <ul class="filter-list list-unstyled pl-2">
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="market-option-1" value="market-option-1">
                            <label class="form-check-label" for="market-option-1">Market Option 1</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="market-option-2" value="market-option-2">
                            <label class="form-check-label" for="market-option-2">Market Option 2</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="market-option-3" value="market-option-3">
                            <label class="form-check-label" for="market-option-3">Market-Option 3</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="market-option-4" value="market-option-4">
                            <label class="form-check-label" for="market-option-4">Market-Option 4</label>
                        </li>
                    </ul>
                </div>
            </div>
            <div id="select-symbols" class="row select-filters select-symbols-instruments-filters p-4">
                <div class="select-heading col-4 offset-5 pl-2">
                    <h6 class="small-sub-heading">Select symbols</h6>
                </div>
                <div class="col-4 offset-5 pt-2 select-filter-items">
                    <ul class="filter-list list-unstyled pl-2">
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="symbol-option-1" value="symbol-option-1">
                            <label class="form-check-label" for="symbol-option-1">Symbol Option 1</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="symbol-option-2" value="symbol-option-2">
                            <label class="form-check-label" for="symbol-option-2">Symbol Option 2</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="symbol-option-3" value="symbol-option-3">
                            <label class="form-check-label" for="symbol-option-3">Symbol Option 3</label>
                        </li>
                        <li class="list-inline-item"> 
                            <input class="form-check-input" type="checkbox" id="symbol-option-4" value="symbol-option-4">
                            <label class="form-check-label" for="symbol-option-4">Symbol Option 4</label>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.bundle.min.js" integrity="sha384-pjaaA8dDz/5BgdFUPX6M/9SUZv4d12SUPF0axWc+VRZkx5xU3daN+lYb49+Ax+Tl" crossorigin="anonymous"></script>
    

\$\endgroup\$
  • \$\begingroup\$ Wow so close! I just see one very minor (visual) defect where once either of the 'select-filters' div shows then you click on the title 'Select markets' or 'Select symbols' the div starts to collapse before the script triggers the reverse again. Can I also ask for you a quick rundown of how this works? I am still learning. Thanks man. \$\endgroup\$ – Kerry7777 Jan 26 at 6:19
  • \$\begingroup\$ I've made some edits to address that and to explain the sequencing and logic. If something still doesn't make sense, just ask. \$\endgroup\$ – Oh My Goodness Jan 26 at 7:13
  • \$\begingroup\$ Works like a charm now, +1 for the explanation. Think I will need to read it a few times. I can't see the accept answer check/tick under the up/down arrows? Thanks again \$\endgroup\$ – Kerry7777 Jan 26 at 7:42
  • \$\begingroup\$ because your account and the posting account are not the same. Request your account be merged with the unregistered account via the contact link in the lower left corner of the page. \$\endgroup\$ – Oh My Goodness Jan 26 at 15:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.