-1

I have a Script that is used to filter drop-down (Country code selection) options with live search. but the problem is I want to show a option named "No Data Found" when their is no exact match found from the HTML value.

Currently my code removes all div's (drop-down options) if the country name is not matches with the HTML value and only the Search Box appears, so I want to show a option named "No Data Found" just after the Search Box which I have currently commented in my HTML Snippet code. When all drop-down option disappears.

I have tried but unable find the solution for this problem.

Output I'm getting - enter image description here

Output I want - enter image description here

I want to show a option box with text "No Data Found" just after the Search Box, if no match found and all country names disappears/hidden and hide the option "No Data Found" if at least minimum any one country name is visible.

Thanks for your time and efforts.

// Get dropdowns and form
const dropdowns = document.querySelectorAll('[data-dropdown]');
const form = document.querySelector('form');

// Check if dropdowns exist on page
if(dropdowns.length > 0) {
  // Loop through dropdowns and create custom dropdown for each select element
  dropdowns.forEach(dropdown => {
    createCustomDropdown(dropdown);
  });
}

// Check if form element exist on page
if(form !== null) {
  // When form is submitted console log the value of the select field
  form.addEventListener('submit', (e) => {
    e.preventDefault();
    console.log('Selected country:', form.querySelector('[name="country"]').value);
  });
}

// Create custom dropdown
function createCustomDropdown(dropdown) {
  // Get all options and convert them from nodelist to array
  const options = dropdown.querySelectorAll('option');
  const optionsArr = Array.prototype.slice.call(options);

  // Create custom dropdown element and add class dropdown to it
  // Insert it in the DOM after the select field
  const customDropdown = document.createElement('div');
  customDropdown.classList.add('dropdown');
  dropdown.insertAdjacentElement('afterend', customDropdown);

  // Create element for selected option
  // Add class to this element, text from the first option in select field and append it to custom dropdown
  const selected = document.createElement('div');
  selected.classList.add('dropdown__selected');
  selected.textContent = optionsArr[0].textContent;
  customDropdown.appendChild(selected);

  // Create element for dropdown menu, add class to it and append it to custom dropdown
  // Add click event to selected element to toggle dropdown menu
  const menu = document.createElement('div');
  menu.classList.add('dropdown__menu');
  customDropdown.appendChild(menu);
  selected.addEventListener('click', toggleDropdown.bind(menu));

  // Create serach input element
  // Add class, type and placeholder to this element and append it to menu element
  const search = document.createElement('input');
  search.placeholder = 'Search...';
  search.type = 'text';
  search.classList.add('dropdown__menu_search');
  menu.appendChild(search);

  // Create wrapper element for menu items, add class to it and append to menu element
  const menuItemsWrapper = document.createElement('div');
  menuItemsWrapper.classList.add('dropdown__menu_items');
  menu.appendChild(menuItemsWrapper);

  // Loop through all options and create custom option for each option and append it to items wrapper element
  // Add click event for each custom option to set clicked option as selected option
  optionsArr.forEach(option => {
    const item = document.createElement('div');
    item.classList.add('dropdown__menu_item');
    item.dataset.value = option.value;
    item.textContent = option.textContent;
    menuItemsWrapper.appendChild(item);

    item.addEventListener('click', setSelected.bind(item, selected, dropdown, menu));
  });

  // Add selected class to first custom option
  menuItemsWrapper.querySelector('div').classList.add('selected');

  // Add input event to search input element to filter items
  // Add click event to document element to close custom dropdown if clicked outside of it
  // Hide original dropdown(select)
  search.addEventListener('input', filterItems.bind(search, optionsArr, menu));
  document.addEventListener('click', closeIfClickedOutside.bind(customDropdown, menu));
  dropdown.style.display = 'none';
}

// Toggle dropdown
function toggleDropdown() {
  // Check if dropdown is opened and if it is close it, otherwise open it and focus search input
  if(this.offsetParent !== null) {
    this.style.display = 'none';
  }else {
    this.style.display = 'block';
    this.querySelector('input').focus();
  }
}

// Set selected option
function setSelected(selected, dropdown, menu) {
  // Get value and label from clicked custom option
  const value = this.dataset.value;
  const label = this.textContent;

  // Change the text on selected element
  // Change the value on select field
  selected.textContent = label;
  dropdown.value = value;

  // Close the menu
  // Reset search input value
  // Remove selected class from previously selected option and show all divs if they were filtered
  // Add selected class to clicked option
  menu.style.display = 'none';
  menu.querySelector('input').value = '';
  menu.querySelectorAll('div').forEach(div => {
    if(div.classList.contains('selected')) {
      div.classList.remove('selected');
    }
    if(div.offsetParent === null) {
      div.style.display = 'block';
    }
  });
  this.classList.add('selected');
}

// Filter items
function filterItems(itemsArr, menu) {
  // Get all custom options
  // Get the value of search input and convert it to all lowercase characters
  // Get filtered items
  // Get the indexes of filtered items
  const customOptions = menu.querySelectorAll('.dropdown__menu_items div');
  const value = this.value.toLowerCase();
  const filteredItems = itemsArr.filter(item => item.value.toLowerCase().includes(value));
  const indexesArr = filteredItems.map(item => itemsArr.indexOf(item));

  // Check if option is not inside indexes array and hide it and if it is inside indexes array and it is hidden show it
  itemsArr.forEach(option => {
    if(!indexesArr.includes(itemsArr.indexOf(option))) {
      customOptions[itemsArr.indexOf(option)].style.display = 'none';
    }else {
      if(customOptions[itemsArr.indexOf(option)].offsetParent === null) {
        customOptions[itemsArr.indexOf(option)].style.display = 'block';
      }
    }
  });
}

// Close dropdown if clicked outside dropdown element
function closeIfClickedOutside(menu, e) {
  if(e.target.closest('.dropdown') === null && e.target !== this && menu.offsetParent !== null) {
    menu.style.display = 'none';
  }
}
@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');

:root {
  --primary-color: #009e6c;
  --border-color: #eee;
}

* {
  box-sizing: border-box;
  margin: 0;
}

body {
  font-family: 'Roboto', sans-serif;
  font-size: 16px;
  line-height: 1.5;
}

header {
  background-color: var(--primary-color);
  color: #fff;
  text-align: center;
  padding: 50px 0;
  margin-bottom: 50px;
}

.container {
  max-width: 600px;
  margin: 0 auto;
  padding-bottom: 50px;
}

.form {
  border: 1px solid var(--border-color);
  padding: 40px;
}

.form__group {
  margin-bottom: 20px;
}

.form__group label {
  display: block;
  font-size: 14px;
  margin-bottom: 5px;
}

.dropdown {
  position: relative;
}

.dropdown__selected {
  display: flex;
  align-items: center;
  width: 100%;
  height: 40px;
  padding: 0 20px 0 10px;
  font-size: 14px;
  border: 1px solid var(--border-color);
  position: relative;
  cursor: pointer;
  transition: box-shadow .3s ease;
}

.dropdown__selected::after {
  top: calc(50% - 2px);
  right: 10px;
  border: solid transparent;
  content: '';
  height: 0;
  width: 0;
  position: absolute;
  border-top-color:#000;
  border-width: 4px;
  margin-left: -4px;
}

.dropdown__selected:hover {
  box-shadow: 0 0 5px rgba(0,0,0,0.1);
}

.dropdown__menu {
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  border: 1px solid var(--border-color);
  border-top: 0;
  background-color: #fff;
  z-index: 5;
  display: none;
}

.dropdown__menu_items {
  max-height: 210px;
  overflow-y: auto;
}

.dropdown__menu_search {
  display: block;
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--border-color);
  padding: 12px;
  outline: 0;
  background-color: #f9f9f9;
}

.dropdown__menu_item {
  padding: 10px;
  border-bottom: 1px solid var(--border-color);
  font-size: 14px;
  cursor: pointer;
}

.dropdown__menu_item:last-child {
  border-bottom: 0;
}

.dropdown__menu_item:hover {
  background-color: var(--border-color);
}

.dropdown__menu_item.selected,
.dropdown__menu_item.selected:hover {
  background-color: var(--primary-color);
  color: #fff;
}

.btn {
  display: inline-flex;
  align-items: center;
  padding: 10px 20px;
  background-color: var(--primary-color);
  color: #fff;
  border: 0;
  outline: 0;
  cursor: pointer;
}
  <div class="container">
    <form class="form">
      <div class="form__group">
        <label for="country">Countries</label>
        <select id="country" name="country" data-dropdown>
          <option value="">Please select a country</option>
          <option value="Afganistan">Afghanistan</option>
          <option value="Albania">Albania</option>
          <option value="Algeria">Algeria</option>
          <option value="American Samoa">American Samoa</option>
          <option value="Andorra">Andorra</option>
          <option value="Angola">Angola</option>
          <option value="Anguilla">Anguilla</option>
          <option value="Antigua & Barbuda">Antigua & Barbuda</option>
          <option value="Argentina">Argentina</option>
          <option value="Armenia">Armenia</option>
          <option value="Aruba">Aruba</option>
          <option value="Australia">Australia</option>
          <option value="Austria">Austria</option>
          <option value="Bonaire">Bonaire</option>
          <option value="Bosnia & Herzegovina">Bosnia & Herzegovina</option>
          <option value="Botswana">Botswana</option>
          <option value="Brazil">Brazil</option>
          <option value="British Indian Ocean Ter">British Indian Ocean Ter</option>
          <option value="Brunei">Brunei</option>
          <option value="Bulgaria">Bulgaria</option>
          <option value="Virgin Islands (USA)">Virgin Islands (USA)</option>
          <option value="Wake Island">Wake Island</option>
          <option value="Wallis & Futana Is">Wallis & Futana Is</option>
          <option value="Yemen">Yemen</option>
          <option value="Zaire">Zaire</option>
          <option value="Zambia">Zambia</option>
          <option value="Zimbabwe">Zimbabwe</option>
         <!-- <option value="N-D-F">No Data Found</option> -->
       </select>
      </div>

      <button type="submit" class="btn">Submit</button>
    </form>
  </div>
Gupa Dutta
  • 67
  • 5

1 Answers1

1

I modified this part and I think it "kind of" works:

function filterItems(itemsArr, menu) {
  // Get all custom options
  // Get the value of search input and convert it to all lowercase characters
  // Get filtered items
  // Get the indexes of filtered items
  const customOptions = menu.querySelectorAll('.dropdown__menu_items div');
  const value = this.value.toLowerCase();
  const filteredItems = itemsArr.filter(item => item.value.toLowerCase().includes(value));
  const indexesArr = filteredItems.map(item => itemsArr.indexOf(item));

  // Check if option is not inside indexes array and hide it and if it is inside indexes array and it is hidden show it
  var nvi=itemsArr.length;
  itemsArr.forEach(option => {
    if(!indexesArr.includes(itemsArr.indexOf(option))) {
      customOptions[itemsArr.indexOf(option)].style.display = 'none';
      nvi-=1;
      if(nvi <= 0) {
        customOptions[itemsArr.length-1].style.display = 'block';
      }
    }
    else {
      if(customOptions[itemsArr.indexOf(option)].offsetParent === null) {
        customOptions[itemsArr.indexOf(option)].style.display = 'block';
      }
    }
  });
}

although, you should tweak it a little more

dummycode
  • 80
  • 5
  • Sir if we add the "No Data Found" string using innerHTML in the last option of select menu, than the "No Data Found" option is also get selectable same as country name, how to exclude it from selection? – Gupa Dutta Dec 21 '22 at 17:44
  • you can just hide it whenever there are "other options" that are visible – dummycode Dec 21 '22 at 23:23
  • Sir I have found a bug on this code when we select any country from the list the last option named "no data found" appears on this dropdown menu how can i fix this problem. – Gupa Dutta Dec 23 '22 at 16:51