Skip to Main Content

APEX and shuttle filter - Revisited

Previously I did write post about APEX and shuttle filter. I received comments that filtering does not work when shuttle have parent cascading item. Issue was that JavaScript code stores shuttle values to variable for filtering only on page load.

I did receive also proposal to add button for clearing filter item. This is also included to new JavaScript code along with some style changes for APEX 19.2.

Here is modified code for page JavaScript Function and Global Variable Declaration:

(function($) {
  $.fn.htmldbShuttlefilter = function(options) {

    options = $.extend({}, {
      "filterPlaceholder": "Filter",
      "buttonTitle": "Clear filter",
      "buttonClass": [
        ,"a-Button"
        ,"a-Button--noLabel"
        ,"a-Button--withIcon"
        ,"a-Button--small"
        ,"a-Button--noUI"
        ,"a-Button--shuttle"
        ,"margin-top-none"
      ],
      "buttonIcon": "fa-times"
    }, options);

    function getShuttleValues(elem$) {
      return elem$.children("option").map(function() {
        return {
          text: $(this).text(),
          value: $(this).val()
        };
      });
    }

    return this.each(function(i) {

      var $self = $(this),

        shuttleResetBtnId = $self.attr("id") + "_RESET",
        $select = $self.find("select"),

        // get shuttle values
        shuttleValues = getShuttleValues($select),

        // filter reset button
        $resetBtn = $("<button/>", {
          "type": "button",
          "title": options.buttonTitle,
          "aria-label": options.buttonTitle,
          "class": options.buttonClass.join(" "),
          "css": {
            "padding": "4px"
          }
        }).append(
          $("<span/>", {
            "aria-hidden": "true",
            "class": "a-Icon fa " + options.buttonIcon,
          })
        ).click(function() {
          // clear filter text field
          $filter.val("").keyup();
        }),

        // filter text field
        $filter = $("<input/>", {
          "type": "text",
          "value": "",
          "autocomplete": "off",
          "placeholder": options.filterPlaceholder,
          "class": "text_field apex-item-text",
          "css": {
            "width": "100%"
          }
        }).keyup(function() {

          // filter shuttle when typing to text field
          var filterval = new RegExp("^" + $(this).val() + ".*", "i"),
            selectedValues = $select.eq(1).children("option").map(function() {
              return $(this).val();
            });

          // empty shuttle available values
          $select.eq(0).empty();
          // add values that match filter criteria
          $.each(shuttleValues, function(idx, obj) {
            if (
              obj.text.match(filterval) &&
              $.inArray(obj.value, selectedValues) < 0
            ) {
              $select.eq(0).append(new Option(obj.text, obj.value));
            }
          });
        });

      // add needed elements to page
      $self.prepend(
        $("<div/>", {
          "class": "t-Form-itemWrapper"
        })
        .append($filter).append(
          $("<span/>", {
            "class": "t-Form-itemText t-Form-itemText--post"
          }).append($resetBtn)
        )

      ).on("apexafterrefresh", function() {
        // initiliaze filter when shuttle is refreshed by parent item
        $filter.val("");
        shuttleValues = getShuttleValues($select);
      });

      // clear also filter from shuttle reset button
      $("#" + shuttleResetBtnId).click(function() {
        $filter.val("");
      });
    });
  }
})(apex.jQuery);

If you like add filter to all shuttles in page, then add to page JavaScript Execute when Page Loads:

$(".apex-item-group--shuttle").htmldbShuttlefilter();

Depending on your need, change jQuery selector.

See working example where Dept shuttle is parent for Emp.

Comments

  • Scott Sutherland 29 May 2022

    I'm busy learning APEX and I'm playing around with the Shuttle feature. I tried this by simply following instructions and cutting and pasting in the correct field. This worked the first time, exactly as expected even though my application is probably unconnected wrt data to anything you have done.
    Absolutely fine piece of coding - I salute your expertise.

  • Johan de Vries 3 Jul 2020

    Nice! The only thing is that the filter works only at the start of the line, if you omit the "^" in the regexp, it works on the whole field.