Posted in JavaScript/jQuery Plugins, Power Apps Portals

Power Pages – Autocomplete Lookup / Dropdown

Basic Forms and Advanced Forms in Power Pages are an amazing way to quickly expose Dataverse data to external users for data manipulation.

The way Power Pages works is by reading the Dataverse form metadata to render the controls on the page. Using Basic Form/Advanced Form Metadata, Power Pages also allows us to control styling and behaviour to controls.

One common question I receive is how to convert a dropdown into a autocomplete control, and that’s what we’ll see in this post. Here is an example of what we are about to achieve:

It’s probably obvious, but worth mentioning that this logic is only applicable for the following type of controls:

  • Choices (OptionSet)
  • Lookups (rendered as dropdown via metadata)

I will describe here what my code below is doing, and the things I have considered when putting this together:

  • The function ConvertSelectToAutocomplete takes two arguments:
    • selectName: the schema name of your column (i.e. primarycontactid)
    • selectPlaceholder: optional parameter if you want a placeholder text when it’s blank (i.e. Please start typing…)
  • The function will copy a few elements from the original select element, for example Classes and Readonly attributes
  • Then I am creating a new <input> element pointing to an empty <datalist> and adding this element to the page
  • Now what I do is loop through all <option> within the original <select> element and add the options to the new datalist
  • The original <select> element is no longer necessary, so we can hide it from the page with a .hide()

All actions above are sufficient to convert your dropdown to a HTML5 autocomplete dropdown, but there are still a few more things to get the full solution working properly:

  • If the record being opened already contains value in the Choices/Lookup column, we need to make sure to populate with the original value. For this we will check the current value and try to find the correspondent item within the dataset
  • The last action here is to attach a logic to the OnChange event, the reason for this is that we need to make sure to keep the original column element in the page up to date with the newly selected value as in the form submit is the original element that will be sent to the server

Before we get to the full code, it’s important to note a few things:

  1. Dataset value
    • The control uses a dataset for holding the options available in the dropdown. The dataset value attribute is the text displayed within the dropdown, so I am creating a separate data-value to hold the actual id/value of the item
    • Because of that, every time we need to get the data-value, it has to be done by finding the element within the dataset list (by text)
    • In other words, for this to work properly, your dataset needs to have unique texts, otherwise it might find the wrong item
  2. Invalid entry
    • By default, this control allows you to add an entry that is not listed within the dataset, so we need to prevent this from happening
    • In my code, what I am doing is simply ignoring and removing the selected text, however you can add an error message in the code if it you prefer
$(document).ready(function () {
    ConvertSelectToAutocomplete("<your optionset/lookup dropdown here>");
});

function ConvertSelectToAutocomplete(selectName, selectPlaceholder) {
    selectPlaceholder = selectPlaceholder ?? "";
    var selectElement = $("#" + selectName);
    var selectElementClass = selectElement.attr("class");
    var readonly = $(selectElement).attr("readonly") ?? "";
    var autoCompleteElementId = selectName + "-autocomplete";
    var autoCompleteDatasetId = selectName + "-data";
    var autoCompleteElement = '<input name="' + autoCompleteElementId + '" id="' + autoCompleteElementId + '" class="' + selectElementClass + '" list="' + autoCompleteDatasetId + '" placeholder="' + selectPlaceholder + '" ' + readonly + '><datalist id="' + selectName + '-data"></datalist>';
    var options = "";

    $(selectElement).parent().append(autoCompleteElement);
    $("#" + selectName + " option").each(function (index, o) {
        options += '<option data-value="' + o.value + '" value="' + o.text + '"/>';
    });
    $("#" + autoCompleteDatasetId).html(options);

    $(selectElement).hide();

    var currentSelectedValue = $(selectElement).val();
    if (!!currentSelectedValue) {
        $("#" + autoCompleteElementId).val($(selectElement).find("option:selected").text());
    }

    $("#" + autoCompleteElementId).on("change", function () {
        var selectedValue = $("#" + autoCompleteDatasetId + " option[value='" + $("#" + autoCompleteElementId).val() + "']").attr("data-value");
        selectElement.val(selectedValue);
        if (typeof selectedValue === "undefined") {
            $("#" + autoCompleteElementId).val("");
            // optionally you can add an error message here
        };
    });
};

Conclusion

This is a nice client-side script logic to enhance the user experience in your Portals. I probably wouldn’t use this in every scenario, if you have just a few options like Yes/No/Blank, I would probably not use this; but if your list goes beyond that with 10+ options, this might improve the way users are filling in forms.

Leave a comment