Home > Software engineering >  How to detect when select menu is active with vanillajs
How to detect when select menu is active with vanillajs

Time:12-21

I have multiple select menus and for all of them, I want to add the same functionality. I want to change the arrow position based on if the select drop down menu is active or not. Keep the down arrow if it is not active and change the arrow to up side if the select menu is active. For that, I have below js code but, it did not work, I tried using active() method but, got this error

Uncaught TypeError: selectMenus[i].active is not a function

Below is code that i tried

 const selectMenus = document.getElementsByClassName('select-menu');
    for (let i = 0; i < selectMenus.length; i  ) {
        selectMenus[i].addEventListener("click", function (e) {
            if (selectMenus[i].active()) {
                console.log("yeeeee")
            }
            selectMenus[i].style.backgroundImage = `url("data:image/svg xml,")`;
        });
    }

Now, the question is, how do I change the direction of the arrow based on the active status of select menu drop down? Can it be done in css? I tried to apply select-menu:focus pseudo selector but, that does not work the way I want it to work. That way, the direction of arrow only changes when I click outside of the select menu. So, Initially it is down direction arrow, when click select menu, it is changed to up direction and when clicked again, the arrow direction stays up direction even the drop down menu is not active. I guess that makes sense because the select menu is still on focus state.

The css for select menu

.select-menu {
    background-image: url("data:image/svg xml,");
}

.select-menu:focus {
    background-image: url('data:image/svg xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"  viewBox="0 0 16 16"><path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/></svg>');
}

The html

<select name="options[20][year]" id="options_20_year"  title="" data-role="calendar-dropdown" data-calendar-role="year" data-canvas-element="date_year" data-selector="options[20][year]" x-on:input="updateCertificateCanvas()" x-on:change="updateCustomOptionValue($dispatch, 'year', $event.target)" data-validate="{&quot;datetime-validation&quot;: true}">
<option value="">-</option><option value="1900">1900</option><option value="1901">1901</option><option value="1902">1902</option><option value="1903">1903</option><option value="1904">1904</option><option value="1905">1905</option><option value="1906">1906</option><option value="1907">1907</option><option value="1908">1908</option><option value="1909">1909</option><option value="1910">1910</option><option value="1911">1911</option><option value="1912">1912</option><option value="1913">1913</option><option value="1914">1914</option><option value="1915">1915</option><option value="1916">1916</option><option value="1917">1917</option><option value="1918">1918</option><option value="1919">1919</option><option value="1920">1920</option><option value="1921">1921</option><option value="1922">1922</option><option value="1923">1923</option><option value="1924">1924</option><option value="1925">1925</option><option value="1926">1926</option><option value="1927">1927</option><option value="1928">1928</option><option value="1929">1929</option><option value="1930">1930</option><option value="1931">1931</option><option value="1932">1932</option><option value="1933">1933</option><option value="1934">1934</option><option value="1935">1935</option><option value="1936">1936</option><option value="1937">1937</option><option value="1938">1938</option><option value="1939">1939</option><option value="1940">1940</option><option value="1941">1941</option><option value="1942">1942</option><option value="1943">1943</option><option value="1944">1944</option><option value="1945">1945</option><option value="1946">1946</option><option value="1947">1947</option><option value="1948">1948</option><option value="1949">1949</option><option value="1950">1950</option><option value="1951">1951</option><option value="1952">1952</option><option value="1953">1953</option><option value="1954">1954</option><option value="1955">1955</option><option value="1956">1956</option><option value="1957">1957</option><option value="1958">1958</option><option value="1959">1959</option><option value="1960">1960</option><option value="1961">1961</option><option value="1962">1962</option><option value="1963">1963</option><option value="1964">1964</option><option value="1965">1965</option><option value="1966">1966</option><option value="1967">1967</option><option value="1968">1968</option><option value="1969">1969</option><option value="1970">1970</option><option value="1971">1971</option><option value="1972">1972</option><option value="1973">1973</option><option value="1974">1974</option><option value="1975">1975</option><option value="1976">1976</option><option value="1977">1977</option><option value="1978">1978</option><option value="1979">1979</option><option value="1980">1980</option><option value="1981">1981</option><option value="1982">1982</option><option value="1983">1983</option><option value="1984">1984</option><option value="1985">1985</option><option value="1986">1986</option><option value="1987">1987</option><option value="1988">1988</option><option value="1989">1989</option><option value="1990">1990</option><option value="1991">1991</option><option value="1992">1992</option><option value="1993">1993</option><option value="1994">1994</option><option value="1995">1995</option><option value="1996">1996</option><option value="1997">1997</option><option value="1998">1998</option><option value="1999">1999</option><option value="2000">2000</option><option value="2001">2001</option><option value="2002">2002</option><option value="2003">2003</option><option value="2004">2004</option><option value="2005">2005</option><option value="2006">2006</option><option value="2007">2007</option><option value="2008">2008</option><option value="2009">2009</option><option value="2010">2010</option><option value="2011">2011</option><option value="2012">2012</option><option value="2013">2013</option><option value="2014">2014</option><option value="2015">2015</option><option value="2016">2016</option><option value="2017">2017</option><option value="2018">2018</option><option value="2019">2019</option><option value="2020">2020</option><option value="2021">2021</option><option value="2022" selected="selected">2022</option>
</select>

<select name="options[20][month]" id="options_20_month"  title="" data-role="calendar-dropdown" data-calendar-role="month" data-canvas-element="date_month" data-selector="options[20][month]" x-on:input="updateCertificateCanvas()" x-on:change="updateCustomOptionValue($dispatch, 'month', $event.target)" data-validate="{&quot;datetime-validation&quot;: true}">
<option value="">-</option><option value="1">Jan</option><option value="2">Feb</option><option value="3">Mar</option><option value="4">Apr</option><option value="5">May</option><option value="6">Jun</option><option value="7">Jul</option><option value="8">Aug</option><option value="9">Sep</option><option value="10">Oct</option><option value="11">Nov</option><option value="12" selected="selected">Dec</option>
</select>

CodePudding user response:

This is as close as I can get it using pure CSS/HTML. I've wrapped the select elements in a wrapper div and used the :focus-within pseudo selector to see if the underlying button has focus. The only clunky bit if you click on the button to close the dropdown the arrow doesn't revert to it's original state. Have a look and see what you think. I've just used unicode characters for the up/down arrows but you could easily replace this with SVG or background images.

.select-container {
  display:inline-block;
  position:relative;
  border:1px solid gray;
  background-color:lightgray;
  border-radius: 0.25rem;
}

.select-container::after {
  content: "▲";
  position: absolute;
  display:grid;
  place-items:center;
  right:0;
  top:0;
  height:100%;
  width:1rem;
  background-color:lightgray;
  pointer-events:none;
}

.select-container:focus-within::after {
  content: "▼"
}

.select-container select {
  background:none;
  border:none;
}
<div class='select-container'><select name="options[20][year]" id="options_20_year"  title="" data-role="calendar-dropdown" data-calendar-role="year" data-canvas-element="date_year" data-selector="options[20][year]" x-on:input="updateCertificateCanvas()" x-on:change="updateCustomOptionValue($dispatch, 'year', $event.target)" data-validate="{&quot;datetime-validation&quot;: true}">
<option value="">-</option><option value="2018">2018</option><option value="2019">2019</option><option value="2020">2020</option><option value="2021">2021</option><option value="2022" selected="selected">2022</option>
</select>
</div>

<div class='select-container'>
<select name="options[20][month]" id="options_20_month"  title="" data-role="calendar-dropdown" data-calendar-role="month" data-canvas-element="date_month" data-selector="options[20][month]" x-on:input="updateCertificateCanvas()" x-on:change="updateCustomOptionValue($dispatch, 'month', $event.target)" data-validate="{&quot;datetime-validation&quot;: true}">
<option value="">-</option><option value="1">Jan</option><option value="2">Feb</option><option value="3">Mar</option><option value="4">Apr</option><option value="5">May</option><option value="6">Jun</option><option value="7">Jul</option><option value="8">Aug</option><option value="9">Sep</option><option value="10">Oct</option><option value="11">Nov</option><option value="12" selected="selected">Dec</option>
</select>
</div>

CodePudding user response:

Add an focus eventListener to check if an input element is active.

  select.addEventListener('focus', e=>{
    console.log('is focused/active');
  })

For your style toggling task you can trigger a blur() event after selecting an option.

let selects = document.querySelectorAll("select");
selects.forEach((select) => {
  let hasFocus = false;
  select.addEventListener("click", (e) => {
    if (hasFocus) {
      e.currentTarget.blur();
      hasFocus = false;
    } else {
      hasFocus = true;
    }
  });

  select.addEventListener("change", (e) => {
    e.currentTarget.blur();
  });
});
select {
  appearance: none;
  background: none;
  width: 25%
}

.select-menu {
  background-repeat: no-repeat;
  background-position: right top;
  background-image: url("data:image/svg xml,");
}

.select-menu:focus {
  background-image: url('data:image/svg xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"  viewBox="0 0 16 16"><path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/></svg>');
}
<select name="options[20][year]" id="options_20_year"  title="" data-role="calendar-dropdown" data-calendar-role="year" data-canvas-element="date_year"
  data-selector="options[20][year]" x-on:input="updateCertificateCanvas()" x-on:change="updateCustomOptionValue($dispatch, 'year', $event.target)" data-validate="{&quot;datetime-validation&quot;: true}">
  <option value="2000">2000</option>
  <option value="2001">2001</option>
  <option value="2002">2002</option>
  <option value="2003">2003</option>
  <option value="2004">2004</option>
  <option value="2005">2005</option>
  <option value="2006">2006</option>
  <option value="2007">2007</option>
  <option value="2008">2008</option>
  <option value="2009">2009</option>
  <option value="2010">2010</option>
  <option value="2011">2011</option>
  <option value="2012">2012</option>
  <option value="2013">2013</option>
  <option value="2014">2014</option>
  <option value="2015">2015</option>
  <option value="2016">2016</option>
  <option value="2017">2017</option>
  <option value="2018">2018</option>
  <option value="2019">2019</option>
  <option value="2020">2020</option>
  <option value="2021">2021</option>
  <option value="2022" selected="selected">2022</option>
</select>

<select name="options[20][month]" id="options_20_month"  title="" data-role="calendar-dropdown" data-calendar-role="month" data-canvas-element="date_month"
  data-selector="options[20][month]" x-on:input="updateCertificateCanvas()" x-on:change="updateCustomOptionValue($dispatch, 'month', $event.target)" data-validate="{&quot;datetime-validation&quot;: true}">
  <option value="">-</option>
  <option value="1">Jan</option>
  <option value="2">Feb</option>
  <option value="3">Mar</option>
  <option value="4">Apr</option>
  <option value="5">May</option>
  <option value="6">Jun</option>
  <option value="7">Jul</option>
  <option value="8">Aug</option>
  <option value="9">Sep</option>
  <option value="10">Oct</option>
  <option value="11">Nov</option>
  <option value="12" selected="selected">Dec</option>
</select>

  • Related