Skip to main content

Adobe

How to Add a Filter to AEM Granite Select Widget

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.

Tags

Thoughts on “How to Add a Filter to AEM Granite Select Widget”

  1. Is this compatible with multi select. I am see some issue if follow this approach for my select field which takes multiple values.

  2. Its not compatible with multiselect on AEM 65. On filter focusout its removing existing values.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Ahmed Musallam, Adobe Technical Lead

Ahmed is an Adobe Technical Lead and expert in the Adobe Experience Cloud.

More from this Author

Categories
Follow Us