Adobe Experience Manager’s Granite Select Widget is a simple dropdown widget that you add to dialogs and page properties to allow users to pick an option from a list. But, the list is not searchable.
To add searchability, OOTB, you have to use the Autocomplete widget. This works well in AEM 6.4 but in AEM 6.5, it is deprecated. Besides, it has more advanced options and usages beyond what I’m trying to achieve here.
In this post, I am particularly interested in enhancing the existing Select widget to make the options searchable. And this enhancement would affect all Select widgets no matter where they are used in AEM.
NOTE: this is now part of ACS Commons 4.2.0 release. See the PR for details!
Please note: this was tested and implemented on AEM 6.4.
Here is a preview of the change I have implemented:
And here is the really simple code to get it done:
// new coral text field to be use as filter input function newFilterTextField() { var filter = new Coral.Textfield(); filter.classList.add("coral-Form-field"); filter.placeholder = "filter"; return filter; } /** * validates some assumptions about the select element structure: * 1. it must have a coral-overlay child. * 2. coral-overlay must have a coral-selectlist child. * 3. coral-selectlist must have items. */ function isValidSelectDomStruture(selectEl) { var overlay = selectEl.querySelector("coral-overlay"); var selectList = overlay ? overlay.querySelector("coral-selectlist") : null; var items = selectList ? selectList.items : false; // coral-overlay must exist & coral-selectlist must exist & coral-selectlist must have items. return !!overlay && !!selectList && !!items; } /** * Hides all items on the selectListEl that do not conatain the filterText, ignoring case. * @param {*} selectListEl the "coral-selectlist" element. * @param {*} filterText the search string (filter). */ function filterSelectList(selectListEl, filterText) { selectListEl.items.getAll().forEach(item => { var itemText = item.textContent; var bothNotEmpty = itemText && filterText; var match = bothNotEmpty && itemText.toLowerCase().indexOf(filterText.toLowerCase()) > -1; var eitherIsEmpty = !itemText || !filterText; if (eitherIsEmpty || match) { item.show(); } else { item.hide(); } }); } var ATTR_FILTER_READY = "data-select-filter-ready"; $(document).on("foundation-contentloaded", function(e) { var container = e.target; $("coral-select", container).each((i, el) => { Coral.commons.ready(el, function(selectEl) { if (selectEl.hasAttribute(ATTR_FILTER_READY)) { return; // exit, already initialized. } else { selectEl.setAttribute(ATTR_FILTER_READY, "true"); } // exit here if structure does not match our assumptions if (!isValidSelectDomStruture(selectEl)) { console.info( "Could not add select filter to the following coral select element. It does not follow the specified structure", selectEl ); return; } var filter = newFilterTextField(); var overlay = selectEl.querySelector("coral-overlay"); var selectList = overlay.querySelector("coral-selectlist"); // add the filter field to the beginning of the list selectList.items.add(filter, selectList.items.first()); // apply filter on keyup filter.addEventListener("keyup", function() { var filterValue = filter.value; filterSelectList(selectList, filterValue); }); }); }); });
Add above code to a clientlib with categories="coralui3"
and you are done!
The code above will add the filter field, which will allow you to search through options as illustrated in the GIF above.
Is this compatible with multi select. I am see some issue if follow this approach for my select field which takes multiple values.
You can go ahead and validate if it does. If it does not, open an issue with ACS Commons as an enhancement and I can take a look.
Its not compatible with multiselect on AEM 65. On filter focusout its removing existing values.