leif.frederiksen

Filtering large List Lookup dropdowns

Blog Post created by leif.frederiksen on Dec 22, 2016

Often you will see forms that contain List Lookup controls that draw their data from some list in Sharepoint that contains hundreds or even thousands of elements. This gives the user a less-than-friendly experience trying to find their relevant selection among all those items.

 

Just look at that scroll bar in the following picture - this tells us that there are LOTS of item to select from...

 

 

I set out to create some functionality for filtering those items, so that only items that contained some string entered by the user, would appear. This is the effect I got after implementing the solution described in this post:

 

These are the steps necessary to accomplish this:

 

1) Save the attached JavaScript file in a place from where you can reference it. I usually store my scripts under Site Assets/Scripting. For this example I have stored it as Site Assets/Scripting/NF-Utilities/NF-OptionsFilter.js.

 

I actually use Sharepoint as my source control system, where I only let my users see the published versions. That way I can do development without affecting the users until I am ready. But that's another story 

 

2) Create a Single Line Text Box somewhere in your form - prefereably near the List Lookup control to make it intuitive for the user, that these fields are somehow connected. This is the field that I labelled "Filter replies" in the screenshot above.

3) Go to the Control Settings of the Text Box, and put in a variable name for the field:

4) Now go to the Control Settings of the List Lookup control and assign another variable for this:

5) Open the Settings of the form:

6) Put in a reference to the script under Advanced -> Custom JavaScript Includes:

7) Enter the following code snippet under Custom JavaScript:

    NWF$(document).ready(function(){
        if (Is New Mode || Is Edit Mode) {
            new Filter(varReply, varReplyFilter);
        }
  });
Note: You get the "Is New Mode" and "Is Edit Mode" by using the "Insert reference" button and selecting them under "Common".

 

 

8) Click Save - and that's it. Now you can deploy your form, and make your users a little bit happier 
I hope you find this helpful - happy Nintexing to all of you 
Curious about the code, but don't want to bother downloading it? Here it is for easy access:

var Filter = function (NFselectorControl, NFfilterControl) {
    this.selectorElement = NWF$('#' + NFselectorControl);
    this.filterElement = NWF$('#' + NFfilterControl);

    // The value of the last used filter on the current item is actually stored - we don't want that to be shown, so we clear the field.
    this.filterElement.val("");

    // We only want the filter to be applied after a certain timeout - due to performance. This variable is used to control this.
    this.timeout;

    // Set up the GUI: When filter value is changed, apply the filter...
    this.setupEventHandler(this);
};

Filter.prototype.setupEventHandler = function (object) {

    // Apply the filter when the user inputs something - but wait until a second has passed from the last key stroke.
    this.filterElement.bind("input", function (event) {
        clearTimeout(object.timeout);

        object.timeout = setTimeout(function () {
            var waitDialog = SP.UI.ModalDialog.showWaitScreenWithNoClose(' ', 'Please wait...', 110, 280);
            setTimeout(function () {
                object.applyFilter(object);
                waitDialog.close();
            });

        }, 1000);
     });

    // The value of the selector may have changed due to the filtering. In order to get the new value stored, it is necessary to put the value of the HTML SELECT into the Nintex selector container.
    // See https://community.nintex.com/thread/7059 for more info on this issue.
     this.selectorElement.change(function () {
        var value = NWF$(this).val();
        object.selectorElement.parent().find("input").val(value);
    })
}

Filter.prototype.applyFilter = function (object) {
    // Get the value of the FILTER element.
    var filterValue = object.filterElement.val().toLowerCase();

    // Run through all descendants of the selector that are OPTION elements...
    object.selectorElement.find("OPTION").each(function () {

// NOTE: From v2.9.0.3 the above line must be replaced with:

// object.selectorElement.parent().children(0).find("OPTION").each(function () {

// This is due to changes in Nintex' way to implent the dropdowns.


    var optionValue = NWF$(this).text();

    // If they qualify, and have SPAN as parent, then make them direct children of the SELECT by removing the surrounding SPAN.
    if (optionValue.toLowerCase().indexOf(filterValue) > -1) {
        if (NWF$(this).parent().is("SPAN")) {
            NWF$(this).unwrap();
        }
    }

    // If they do not qualify, and do not have SPAN as parent, then put a SPAN around the element.
    if (optionValue.toLowerCase().indexOf(filterValue) == -1) {
        if (!NWF$(this).parent().is("SPAN")) {
            NWF$(this).wrap("SPAN");
        }
    }
});

    // Make Nintex take notice that the value of the selector may have changed.
    object.selectorElement.trigger("change");
};

 

Update March 1st 2017: Due to changes in Nintex' implementation of the dropdown, a small change has been made to the script. If you are running Nintex Forms v 2.9.3 or newer, then please download and use the NF-OptionsFilter-forms-v2.9.3.0.zip file. Thank you Oliver Schneider for making me aware of this issue.

Outcomes