Searchable Select

by Michael Prosser

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.14.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.14.1/jquery-ui.min.js"></script>
<style>
.searchable-select-component>input[type="search"]{
	width: 100% !important;
}
</style>
<label><select class="searchable dynamic-form-data-component" multiple size="4" autocomplete="off" height="80" id="myController0" name="myController0" required="1" width="220" guid="5d73c643-2fcd-4c88-bca8-67d7f38e8ec9" data-table="facilities" data-table-alias="Facilities" mapto="facility"><option value="" selected="">Select..</option><option value="1000008" data-facility-id="1000008" data-facility-name="Houston TX" data-facility-conventionname="HTX" data-facility-address="12345 No-nome Street" data-facility-city="Houston" data-facility-state="TX" data-facility-zip="45433" data-facility-phone="555-555-5555">Houston TX</option><option value="3" data-facility-id="3" data-facility-name="Mattoon" data-facility-conventionname="MAP" data-facility-address="4159 Enquist Rd" data-facility-city="Matton" data-facility-state="AL" data-facility-zip="V9H 1A4" data-facility-phone="555-555-5555">Mattoon</option><option value="1000004" data-facility-id="1000004" data-facility-name="My Facility" data-facility-conventionname="MFC" data-facility-address="aeewa" data-facility-city="wqewqewq" data-facility-state="AL" data-facility-zip="qwewqe" data-facility-phone="qwe">My Facility</option><option value="1000003" data-facility-id="1000003" data-facility-name="North Plant" data-facility-conventionname="NPL" data-facility-address="qwewqewq" data-facility-city="Farmington" data-facility-state="AL" data-facility-zip="waewae" data-facility-phone="wqewqe">North Plant</option><option value="1000120" data-facility-id="1000120" data-facility-name="test facility" data-facility-conventionname=""...

CSS

.searchable-select-layout{
  z-index: 9999999999;
  perspective: 1000;
}

.searchable-select-layout .aliveComponents{
  perspective: none !important;
}

.searchable-select.hide-searchable{
  height: 1px!important;
  width: 1px !important;
  border: none !important;
  opacity: 0;
  margin: 0px;
  padding: 0px;
  min-height: 0px;
}
.searchable-select.hide-searchable-full{
  display: none;
  position: fixed;
  left: -199999px;
}
.searchable-select-component {
  position: relative;
  width: 300px;
  font-size: 13px;
  font-family: helvetica, serif;
  display: none;
}

.searchable-select-component.active {
  display: inline-block;
  z-index:999;
}



.searchable-select-component[data-multiple].active {
	z-index: initial;
	margin-bottom: 15px;
	width: calc(100% - 106px) !important;
	min-height: 120px !important;
}

label[data-component-label=" "] .searchable-select-component[data-multiple].active {
	width: calc(100% - 6px) !important;
}

.searchable-select-component>input[type="search"] {
  border: solid 1px #ccc;
  border-radius: 5px;
  background-color: #fff;
  color: #222;
  margin-bottom: 4px;
  min-height: 36px;
  padding: 6px;
  padding-left: 26px;
  width: 100%;
  background-image:...

JavaScript

var enable_searchable_list_components = true;

function SearchableSelect(selector,layoutSelector) {
	
  if(typeof(app) != 'undefined'){
  
    if(app){
      
      if(app.editing){
        
        return false;
        
      }
      
    }

  }
  
	
  if(!window.enable_searchable_list_components){ return false; }

  if (selector instanceof jQuery){
	  
	  
	  
  } else {
	  
	  selector = $(selector);
	  
  }

  var t = this;

  selector.find('option').each(function(i){

    $(this).attr('data-index',parseInt(i+1));

  });

  t.maxBeforeScrolling = 15;

  t.compare = function( a, b ) {
    if ( a.index < b.index ){
      return -1;
    }
    if ( a.index > b.index ){
      return 1;
    }
    return 0;
  }



  t.reorderSelectionToTop = function(wasSelected,itemElement,element,arr){

    if(!element.attr('multiple')){

      return false;

    }

    let timer = 0;

    if(itemElement){

      timer = 500;

      if(wasSelected){

        $(itemElement).addClass('out-selection');

      } else {

        $(itemElement).addClass('in-selection');

      }

    }
    

    setTimeout(() => {

      let nav = element.searchInput.find('nav');

      let selections = [];

      for(let i=0;i<arr.length;i++){

        let item = nav.find('button[data-real-value="' + arr[i] + '"]').detach();

        item.index = parseInt(item.attr('data-index'));

        selections.push(item);

      }

      selections.sort( t.compare );

      selections.reverse();

      for(let i=0;i<selections.length;i++){

        nav.prepend(selections[i]);

      }
      
      // now reorder the unselected items

      let unselected = [];

      nav.find('button:not(.selected)').each(function () {

        let item = $(this).detach();

        item.index = parseInt($(this).attr('data-index'));

        unselected.push(item);

      });

      unselected.sort( t.compare...