Filtering Power Pages lists by values on related entities using FetchXML filters

michelcarloMicrosoft 3651 month ago27 Views

When using classic lists in Power Pages, we can select any view from a table to display in our portal, and this view can even be using values from related tables.

The problem

When creating a LookUp set filter on a list in Power Pages, we cannot use values from related tables, even if they are added to the table (as in the example below, we added the accounts that relate to the Portal User field in a ‘Support Tickets’ table):

The options when configuring a LookUp set only bring fields from the current table:

Similarly, for Dynamically LookUp sets, we can only use columns from the primary table.

Prerequisites

The configuration for the sample below is done on the Power Pages Management/Portal Management App.

The simpler solution: Replicate the lookup filter set with a Link-Entity on filters

Here is the trick, we can use a FetchXML filter, and use a link-entity to the accounts table to filter it.

In the example below we have 2 hardcoded filters for 2 different companies (this would be similar to the LookUp set filters we use in Power Pages):

FetchXML code to copy:

 <link-entity name="contact" from="contactid" to="pnp_portaluser" link-type="inner">
      <filter type="or" adx:uiname="Company Name">
        <condition attribute="parentcustomerid" operator="eq" value="5a2b5163-c34d-ef11-bfe2-0022488317e7" uiname="Fabrikam Global" uitype="account" />
        <condition attribute="parentcustomerid" operator="eq" value="2db20c7c-db49-ef11-bfe2-0022488317e7" uiname="Contoso Global" uitype="account" />
      </filter>
    </link-entity>

Each of the options you add as a condition to the filter will appear as a value to be selected. The uiname property dictates how the value labels are displayed, so you can change it to anything you want.

Unfortunately, even if we change the adx:uiname property of the filter it does not reflect on the UI. After saving the filter it will get the display name from the table and not the entity and that is not what we want:

To fix this, we need to add some JavaScript to this list to rename it.

Each filter added into a list gets a ‘name’ property which matches it’s index, So we’ll use it to find the label for it and rename it. For the label for a filter it matches it using the data-filter-id attribute, and for the control itself it matches it using the name attribute.

The filter index is zero index based, so if it’s your third filter in the list, the index will be 2, for example:

JavaScript code for the list JavaScript (add it under the options tab):

$(document).ready(function () {
    // Rename the label to "Company name"    
    $('.entitylist-filter-option-group-label[data-filter-id="2"]').text("Company Name");   
});

After saving the list, the new filter will appear with the updated label:

Results:

When applying the filter, it will filter correctly by the accounts of the contacts associated with the records:

Similarly, we could also use a similar approach for a dynamic filter (for example, automatically generating a dropdown based on the current accounts in Dataverse), so we don’t need to have values hardcoded in the Fetch Filter.

More advanced solution: Dynamic Filter

Instead of using the filter set with options on the Link-Entity filter, you can use a dynamic filter as below:

 <link-entity name="contact" from="contactid" to="pnp_portaluser" link-type="inner">
      <filter adx:uiinputtype="dynamic">
        <condition attribute="parentcustomerid" operator="eq" value=""  adx:uiinputtype="dynamic" />
      </filter>
    </link-entity>

Even though the reference to the inputtype values contains the adx reference, it still works fine on both standard and enhanced data model site types.

In this instance, you will need to inject a dropdown with the values manually, since the dynamic filter does not list any of the values. In the same way, add the JavaScript code sample below to get the accounts and generate a drop-down with them automatically (setting the filter index as a constant now to be used across more code pieces, change the value to your filter index when using this):


$(document).ready(function () {
    const customFilterIndex = 2;//Your filter index as explained on the other sample
     // Rename the label to "Company name"    
    $(`.entitylist-filter-option-group-label[data-filter-id="${customFilterIndex}"]`).text("Company Name");   
    // Fetch accounts using webapi.safeAjax
    webapi.safeAjax({
        type: "GET",
        url: "/_api/accounts?$select=accountid,name",
        contentType: "application/json",
        headers: {
            "Prefer": "odata.include-annotations=*"
        },
        success: function (data, textStatus, xhr) {
            var results = data.value;
// Call the function to populate the dropdown, passing the name attribute dynamically
            populateDropdown(results, customFilterIndex);
        },
        error: function (xhr, textStatus, errorThrown) {
            console.error("Error fetching accounts:", xhr);
        }
    });
    
    function populateDropdown(accounts, filterId) {
        const dropdown = $(`<select class="form-control" name="${filterId}" id="dropdown_${filterId}"></select>`);

        // Add a default empty option
        dropdown.append('<option value="" label=" "> </option>');
        // Loop through the accounts and add options to the dropdown
        accounts.forEach(account => {
            const accountId = account["accountid"]; // Account ID (GUID)
            const accountName = account["name"];   // Account Name (Text)
            // Create the option element dynamically
            const option = `
                <option value="{${accountId}}" label="${accountName}">
                    ${accountName}
                </option>`;
            dropdown.append(option);
        });

        // // Add the dropdown to the DOM       
        $(`li.entitylist-filter-option-group label[data-filter-id="${filterId}"]`)
            .siblings('ul')
            .replaceWith(`
                <div class="input-group entitylist-filter-option-text">
                    <span class="input-group-addon"><span class="fa fa-filter" aria-hidden="true"></span></span>
                </div>
            `);

        //Append the dropdown inside the input group
        $(`li.entitylist-filter-option-group label[data-filter-id="${filterId}"]`)
            .siblings('.input-group')
            .append(dropdown);
    }
});

Prerequisites: To run the code, you need to enable the accounts table for WebAPI and the user needs to have table permissions granted. And also the page where the list is located needs to have the Web API wrapper code added.

After the change is applied, you can see a new filter with all the accounts the user has access to:

When filtering by a company, the records display based on the contacts for that company as expected:

Conclusion

Using a FetchXML list filter with some JavaScript tricks, we can create filters with predefined values or dynamic filters based on related tables and overcome the limitation of using filters only on fields on the current table.

References

How to use the Portal Web API – Microsoft Learn

The post Filtering Power Pages lists by values on related entities using FetchXML filters appeared first on michelcarlo.

Original Post https://michelcarlo.com/2025/01/25/filtering-power-pages-lists-by-values-on-related-entities-using-fetchxml-filters/

Leave a reply

Join Us
  • X Network2.1K
  • LinkedIn3.8k
  • Bluesky0.5K
Support The Site
Events
February 2025
MTWTFSS
      1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28   
« Jan   Mar »
Follow
Sign In/Sign Up Sidebar Search
Popular Now
Loading

Signing-in 3 seconds...

Signing-up 3 seconds...