2

I made a filter with multiple options. As you can see, there are sometimes no results. I give this back to the visitor as user feedback by saying: no results.

Now I want to make it that if certain combinations are made of filters (certain values), it is only possible to use a filter if there are actually values (so hide a option if there is no value on the page). This way I prevent a user from having to make endless filter combinations to find the right results. Can someone help me?

$("select.filterby").change(function() {
  var filters = $.map($("select.filterby").toArray(), function(e) {
    return $(e).val();
  }).join(".");
  $("div#FilterContainer").find("div.job-offer-card").hide();
  if ($("div#FilterContainer").find("div.job-offer-card." + filters).length) {
    $("div#FilterContainer").find("div.job-offer-card." + filters).show();

  } else {
    $("div#FilterContainer").find("div.noresults").show();
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span> View by:</span>


    <label for="location">Location</label>
    <select id="location" class="filterby">
       <option value="all">Show All</option>
       <option value="australia">Australia</option>
       <option value="singapore">Singapore</option>
       <option value="newzealand">New Zealand</option>
       <option value="usa">USA</option>
       <option value="uk">UK</option>
       <option value="vietnam">Vietnam</option>
       <option value="global">Global</option>
       <option value="othercountry">Other</option>
    </select>


    <label for="type">Type</label>
    <select id="type" class="filterby">
       <option value="all">Show All</option>
       <option value="accommodation">Accommodation</option>
       <option value="app">App/Technology</option>
       <option value="business">Business</option>
       <option value="health">Health</option>
       <option value="hospitality">Hospitality</option>
       <option value="education">Education</option>
       <option value="retail">Retail</option>
       <option value="services">Services</option>
       <option value="travel">Travel</option>
    </select>

    <label for="code">Code</label>
    <select id="code" class="filterby">
       <option value="all">Show All</option>
       <option value="001">001</option>
       <option value="002">002</option>
       <option value="003">003</option>
       <option value="004">004</option>
    </select>

<div id="FilterContainer">
  <div class="job-offer-card noresults">
    <p>no results</p>
  </div>
  <div class="job-offer-card all vietnam accommodation travel 004">
    <p>1 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card all vietnam  travel 003">
    <p>2 all vietnam travel</p>
  </div>
  <div class="job-offer-card all vietnam accommodation travel">
    <p>3 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card all australia accommodation travel 003">
    <p>4 all australia accommodation travel</p>
  </div>
  <div class="job-offer-card all australia education">
    <p>5 all australia</p>
  </div>
  <div class="job-offer-card all vietnam newzealand usa accommodation">
    <p>6 all vietnam accommodation</p>
  </div>
  <div class="job-offer-card all vietnam accommodation travel">
    <p>7 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card all vietnam  travel">
    <p>8 all vietnam travel</p>
  </div>
  <div class="job-offer-card all vietnam accommodation travel">
    <p>9 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card all australia accommodation travel">
    <p>10 all australia accommodation travel</p>
  </div>
  <div class="job-offer-card all australia health 001">
    <p>11 all australia</p>
  </div>
  <div class="job-offer-card all vietnam accommodation 002">
    <p>12 all vietnam accommodation</p>
  </div>
</div>
Nimitt Shah
  • 4,477
  • 2
  • 10
  • 21
morrits
  • 81
  • 10
  • Possible duplicate of [Using jQuery, how do you find only visible elements and leave hidden elements alone?](https://stackoverflow.com/questions/16782925/using-jquery-how-do-you-find-only-visible-elements-and-leave-hidden-elements-al) – Simon May 28 '19 at 17:26
  • you want a JS answer? not a jQuery answer ? – Mister Jojo May 28 '19 at 17:32
  • Hi @Simon ! Thanks for your respons. But it is a little bit different. I want to hide an option if there is no certain value, for example: if filter nr. 1 is chosen there are different a less option possible for filter 2 etc. – morrits May 28 '19 at 17:33
  • @MisterJojo yes that's also fine! – morrits May 28 '19 at 17:34
  • Just an improvement: Why look up something and than look it up again? Store it into a variable. `var items = $("div#FilterContainer").find("div.job-offer-card." + filters); if (items.length) {items.show()} else {}` – epascarello May 28 '19 at 18:06
  • @epascarello what part do you mean? – morrits May 28 '19 at 18:12

2 Answers2

1

Solution with dynamic select and dynamic FilterContainer elements showing.

Remark : the class names 001 ... 004 should be changed to _001 ..._004, because they are not valid class names see => Which characters are valid in CSS class names/selectors?
Or it could be more clear to use dataset => https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset

const
    Selects = document.querySelectorAll('select')                      // 3 selects in this story
  , mainFC  = document.querySelector('#FilterContainer')               // result part
  , all_FC  = document.querySelectorAll('#FilterContainer div')        // details result part
  , zeroFC  = document.querySelector('#FilterContainer div.noresults') // when there is nothing
;

var PossibleOptions = new Set();  // set for all options feet in #FilterContainer div

all_FC.forEach(d=>{d.className.split(' ').forEach(c=>{PossibleOptions.add(c)})}) // first attempt

// for the start : set only options availables + onchange listener
Selects.forEach(s=>{                                // for each Select 
  s.querySelectorAll('option').forEach(o=>{         // and for each option, in
    o.disabled = !PossibleOptions.has(o.value);     // is there 1 a result div using this class ?.
    if (o.value==='all') o.selected=true;           // start the select at position for all
  })
  s.onchange = SelecChange;                         // give listener 'change' to function named 'SelecChange'
})



function SelecChange(e)              // for every select action...
{
  //  e.target.value 
  let                               // prepare ;
    List_Selects = []               // - array for all selects value
  , no_FC        = true             // - flag to know if there is no FS as result
  ;
  PossibleOptions.clear();          // new start

  Selects.forEach(s=>{              // make List_Selects
    if(s.value!='all')              // everything is nothing
    { List_Selects.push(s.value) }  // add select value
  });
 
  all_FC.forEach(d=>{               // for each FilterContainer <div> as 'd'
    let ok = true;
    for(let cLS of List_Selects)    // for each option choosed in a select
    { ok = ok && d.classList.contains(cLS) } // check if in class list of the <div>

    if (ok){
      d.classList.remove('noShow');   // so this div will be shown
      d.className.split(' ').forEach(c=>{ PossibleOptions.add(c) }); 
                                      // and all the div class item be added on the set
      no_FC = false;                  // one is enough
    }
    else {
      d.classList.add('noShow');    // soory guy, your not in the team for this time
    }
  })

  // now we have disable all options witch as no reality in FilterContainer
  Selects.forEach(s=>{ 
    s.querySelectorAll('option').forEach(o=>{
      o.disabled = !PossibleOptions.has(o.value);   // PossibleOptions know
    })
  })

  // last things: is there results ?
  if (no_FC) { zeroFC.classList.remove('noShow') }  // there is none
  else       { zeroFC.classList.add('noShow')    }  // there is one (or more)
}
.noShow { display: none }
<h4> View by:</h4>

<label for="location">Location</label>
<select id="location" class="filterby">
    <option value="all">Show All</option>
    <option value="australia">Australia</option>
    <option value="singapore">Singapore</option>
    <option value="newzealand">New Zealand</option>
    <option value="usa">USA</option>
    <option value="uk">UK</option>
    <option value="vietnam">Vietnam</option>
    <option value="global">Global</option>
    <option value="othercountry">Other</option>
</select>

<label for="type">Type</label>
<select id="type" class="filterby">
    <option value="all">Show All</option>
    <option value="accommodation">Accommodation</option>
    <option value="app">App/Technology</option>
    <option value="business">Business</option>
    <option value="health">Health</option>
    <option value="hospitality">Hospitality</option>
    <option value="education">Education</option>
    <option value="retail">Retail</option>
    <option value="services">Services</option>
    <option value="travel">Travel</option>
</select>

<label for="code">Code</label>
<select id="code" class="filterby">
    <option value="all">Show All</option>
    <option value="001">001</option>
    <option value="002">002</option>
    <option value="003">003</option>
    <option value="004">004</option>
</select>
<hr>

<div id="FilterContainer">
  <div class="job-offer-card noresults noShow">
    <p>no results</p>
  </div>
  <div class="job-offer-card all vietnam accommodation travel 004">
    <p>1 all vietnam accommodation travel _004</p>
  </div>
  <div class="job-offer-card all vietnam travel _003">
    <p>2 all vietnam travel _003</p>
  </div>
  <div class="job-offer-card all vietnam accommodation travel">
    <p>3 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card all australia accommodation travel 003">
    <p>4 all australia accommodation travel 003</p>
  </div>
  <div class="job-offer-card all australia education">
    <p>5 all australia education</p>
  </div>
  <div class="job-offer-card all vietnam newzealand usa accommodation">
    <p>6 all vietnam newzealand usa accommodation</p>
  </div>
  <div class="job-offer-card all vietnam accommodation travel">
    <p>7 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card all vietnam travel">
    <p>8 all vietnam travel</p>
  </div>
  <div class="job-offer-card all vietnam accommodation travel">
    <p>9 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card all australia accommodation travel">
    <p>10 all australia accommodation travel</p>
  </div>
  <div class="job-offer-card all australia health 001">
    <p>11 all australia health _001</p>
  </div>
  <div class="job-offer-card all vietnam accommodation 002">
    <p>12 all vietnam accommodation _002</p>
  </div>
</div>

Same Solution but using data-options
=> <div class="job-offer-card" data-options="all vietnam accommodation 002">
( JS =>element.dataset.options)

const
    Selects = document.querySelectorAll('select')                      // 3 selects in this story
  , mainFC  = document.querySelector('#FilterContainer')               // result part
  , all_FC  = document.querySelectorAll('#FilterContainer div')        // details result part
  , zeroFC  = document.querySelector('#FilterContainer div.noresults') // when there is nothing
;

var PossibleOptions = new Set();  // set for all options feet in #FilterContainer div

all_FC.forEach(d=>{ d.dataset.options.split(' ').forEach(c=>{PossibleOptions.add(c)})}) // first attempt

// for the start : set only options availables + onchange listener
Selects.forEach(s=>{                                // for each Select 
  s.querySelectorAll('option').forEach(o=>{         // and for each option, in
    o.disabled = !PossibleOptions.has(o.value);     // is there 1 a result div using this class ?.
    if (o.value==='all') o.selected=true;           // start the select at position for all
  })
  s.onchange = SelecChange;                         // give listener 'change' to function named 'SelecChange'
})

function SelecChange(e)              // for every select action...
{
  //  e.target.value 
  let                               // prepare ;
    List_Selects = []               // - array for all selects value
  , no_FC        = true             // - flag to know if there is no FS as result
  ;
  PossibleOptions.clear();          // new start

  Selects.forEach(s=>{              // make List_Selects
    if(s.value!='all')              // everything is nothing
    { List_Selects.push(s.value) }  // add select value
  });
 
  all_FC.forEach(d=>{               // for each FilterContainer <div> as 'd'
    let
      ok  = true,
      opt = d.dataset.options.split(' ');
 
    for(let cLS of List_Selects)    // for each option choosed in a select
    { ok = ok && opt.includes(cLS) } // check if in class list of the <div>

    if (ok){
      opt.forEach(c=>{ PossibleOptions.add(c) }); // all the data-options item  be added on the set
      d.classList.remove('noShow');              // so this div will be shown
      no_FC = false;                            // one is enough
    }
    else {
      d.classList.add('noShow');    // soory guy, your not in the team for this time
    }
  })

  // now we have disable all options witch as no reality in FilterContainer
  Selects.forEach(s=>{ 
    s.querySelectorAll('option').forEach(o=>{
      o.disabled = !PossibleOptions.has(o.value);   // PossibleOptions know
    })
  })

  // last things: is there results ?
  if (no_FC) { zeroFC.classList.remove('noShow') }  // there is none
  else       { zeroFC.classList.add('noShow')    }  // there is one (or more)
}
.noShow { display: none }
<label for="location">Location</label>
<select id="location" class="filterby">
    <option value="all">Show All</option>
    <option value="australia">Australia</option>
    <option value="singapore">Singapore</option>
    <option value="newzealand">New Zealand</option>
    <option value="usa">USA</option>
    <option value="uk">UK</option>
    <option value="vietnam">Vietnam</option>
    <option value="global">Global</option>
    <option value="othercountry">Other</option>
</select>

<label for="type">Type</label>
<select id="type" class="filterby">
    <option value="all">Show All</option>
    <option value="accommodation">Accommodation</option>
    <option value="app">App/Technology</option>
    <option value="business">Business</option>
    <option value="health">Health</option>
    <option value="hospitality">Hospitality</option>
    <option value="education">Education</option>
    <option value="retail">Retail</option>
    <option value="services">Services</option>
    <option value="travel">Travel</option>
</select>

<label for="code">Code</label>
<select id="code" class="filterby">
    <option value="all">Show All</option>
    <option value="001">001</option>
    <option value="002">002</option>
    <option value="003">003</option>
    <option value="004">004</option>
</select>
<hr>

<div id="FilterContainer">
  <div class="job-offer-card noresults noShow" data-options="all">
    <p>no results</p>
  </div>
  <div class="job-offer-card" data-options="all vietnam accommodation travel 004">
    <p>1 all vietnam accommodation travel _004</p>
  </div>
  <div class="job-offer-card" data-options="all vietnam travel _003">
    <p>2 all vietnam travel _003</p>
  </div>
  <div class="job-offer-card" data-options="all vietnam accommodation travel">
    <p>3 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card" data-options="all australia accommodation travel 003">
    <p>4 all australia accommodation travel 003</p>
  </div>
  <div class="job-offer-card" data-options="all australia education">
    <p>5 all australia education</p>
  </div>
  <div class="job-offer-card" data-options="all vietnam newzealand usa accommodation">
    <p>6 all vietnam newzealand usa accommodation</p>
  </div>
  <div class="job-offer-card" data-options="all vietnam accommodation travel">
    <p>7 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card" data-options="all vietnam travel">
    <p>8 all vietnam travel</p>
  </div>
  <div class="job-offer-card" data-options="all vietnam accommodation travel">
    <p>9 all vietnam accommodation travel</p>
  </div>
  <div class="job-offer-card" data-options="all australia accommodation travel">
    <p>10 all australia accommodation travel</p>
  </div>
  <div class="job-offer-card" data-options="all australia health 001">
    <p>11 all australia health _001</p>
  </div>
  <div class="job-offer-card" data-options="all vietnam accommodation 002">
    <p>12 all vietnam accommodation _002</p>
  </div>
</div>
Mister Jojo
  • 20,093
  • 6
  • 21
  • 40
0

so if I check correctly your question:

const
  All_Select          = document.querySelectorAll('select')
, All_FilterContainer = document.querySelectorAll('#FilterContainer div')
;

var List_of_everthing   = new Set();
All_FilterContainer.forEach(d=>{
  d.className.split(' ').forEach(c=>{List_of_everthing.add(c.toLowerCase())});
})

All_Select.forEach(s=>{
  s.querySelectorAll('option').forEach(o=>{
    o.disabled = !List_of_everthing.has(o.value);
  })
})
Mister Jojo
  • 20,093
  • 6
  • 21
  • 40
  • You are a legend! That just made my day. Thank you very much! – morrits May 28 '19 at 18:08
  • Do you think it possible to keep checking whether a combination is possible? It now seems as if this is only possible in the beginning. With some combinations you get new combinations with the result: no results. – morrits May 28 '19 at 18:16
  • I will look at this later, it requires reflection – Mister Jojo May 28 '19 at 18:22
  • I just see a mass of code, and can't tell at a glance how it differs from the original code in the question. If you explain _what_ you changed/added and _how & why_ it works this would be a _much_ better answer. Remember, SO is here not just to solve the OP's immediate problem, but to help future people who find this Q&A. – Stephen P May 28 '19 at 18:26
  • `@Stephen P` I understand and I will try to be more educational now, but it costs me, because English is not my mother tongue, and that I spend my time translating the masses of stackoverflow information in both directions – Mister Jojo May 28 '19 at 21:53