Advanced Multi-Selector Filtering in Acumatica Modern UI

Acumatica

This article expands on the original MultiSelector example by exploring the logic, patterns, and implementation approach behind enabling multi-value filtering in Acumatica – for both Modern UI and Classic UI.

Filtering data by multiple field values is a common requirement, but Acumatica developers often need more control than the standard selector provides. This article walks through a clean, extensible approach used in real-world implementations.

Final Result

Modern UI

Classic UI

Implementation

Defining the Filter Fields

To allow multi-value selection, we declare two filter fields:

  • DepartmentID

  • LabourItemCD

The key detail is:

ValidateValue = false must be set on PXSelector fields

This disables strict validation and allows multiple values separated by semicolons.

C# Filter DAC Example

🌐
using PX.Data;
using PX.Data.BQL;
using PX.Data.BQL.Fluent;
using PX.Objects.EP;
using PX.Objects.IN;
using System;

namespace MyProject
{
   [Serializable]
   public class Filter : PXBqlTable, IBqlTable
   {
      #region DepartmentID
      [PXString]
      [PXSelector(typeof(SearchFor<EPDepartment.departmentID>),
                  typeof(EPDepartment.departmentID),
                  typeof(EPDepartment.description),
                  ValidateValue = false)]
      [PXUIField(DisplayName = "Department")]
      public virtual string DepartmentID {  get; set; }
      public abstract class departmentID : BqlString.Field<departmentID> { }
      #endregion

      #region LabourItemCD
      [PXString]
      [PXSelector(typeof(SelectFrom<InventoryItem>
          .Where<InventoryItem.itemType.IsEqual<INItemTypes.laborItem>>
          .SearchFor<InventoryItem.inventoryCD>),
                  typeof(InventoryItem.inventoryCD),
                  typeof(InventoryItem.descr),
                  ValidateValue = false)]
      [PXUIField(DisplayName = "Labor Item")]
      public virtual string LabourItemCD { get; set; }
      public abstract class labourItemCD : BqlString.Field<labourItemCD> { }
      #endregion
   }
}

Filtering Logic in the BLC

The Data View Delegate processes values by splitting the multi-selector input into separate values.

Key helper method:

🌐
private static bool MultiSelectorHasValues(string value, out IEnumerable<string> splittedValues)
{
   var hasValues = !string.IsNullOrEmpty(value);
   splittedValues = hasValues ? Regex.Split(value, "; ?").AsEnumerable() : null;
   return hasValues;
}

Full Delegate Logic

🌐
protected virtual IEnumerable employees()
{
   var filter = Filter.Current;

   var employees = new SelectFrom<EPEmployee>.View(this).Select().FirstTableItems;

   if (MultiSelectorHasValues(filter.DepartmentID, out var departmentIDs))
   {
      employees = employees.Where(e => e.DepartmentID.IsIn(departmentIDs));
   }

   if (MultiSelectorHasValues(filter.LabourItemCD, out var laborItemCDs))
   {
      var laborItemIDs = new SelectFrom<InventoryItem>
               .Where<InventoryItem.inventoryCD.IsIn<@P.AsString>>
               .View(this)
               .Select(laborItemCDs)
               .FirstTableItems
               .Select(i => i.InventoryID);

      employees = employees.Where(e => e.LabourItemID.IsIn(laborItemIDs));
   }

   return employees;
}

Modern UI Layout

In Modern UI, multi-select is enabled via the decorator:

🌐
@controlConfig({ multiSelect: true })

TypeScript Example

🌐
@graphInfo({
    graphType: "MyProject.EmployeeListInq",
    primaryView: "Filter",
})
export class EP203100 extends PXScreen {
    Filter = createSingle(Filter);
    Employees = createCollection(EPEmployee);
}

export class Filter extends PXView {    
    @controlConfig({ multiSelect : true })
    DepartmentID : PXFieldState<PXFieldOptions.CommitChanges>;  

    @controlConfig({ multiSelect : true })
    LabourItemCD : PXFieldState<PXFieldOptions.CommitChanges>;
}

HTML Template

🌐
<template>
    <qp-template id="form-Filter" name="1-1">
        <qp-fieldset id="fsColumnA-Filter" view.bind="Filter" slot="A">
            <field name="DepartmentID" ></field>
            <field name="LabourItemCD" ></field>
        </qp-fieldset>
    </qp-template>

    <qp-grid id="grid-Employees" view.bind="Employees"></qp-grid>
</template>

Classic UI Layout

Classic UI implements multi-selection via PXMultiSelector.

🌐
<px:PXMultiSelector CommitChanges="True" runat="server" 
    ID="edDepartmentID" DataField="DepartmentID">
</px:PXMultiSelector>

<px:PXMultiSelector CommitChanges="True" runat="server" 
    ID="edLabourItemCD" DataField="LabourItemCD">
</px:PXMultiSelector>

Possible Improvements

The example intentionally keeps things simple for readability.

However, the query can be optimized:

Option A — Use conditional query composition

Use .WhereAnd<…>() to build filtering into SQL at runtime instead of loading all employees into memory.

Option B — Cache pre-filtered lookups

For large datasets, caching labor items can significantly improve performance.

Conclusion

This enhanced article provides deeper context and explanation behind the original MultiSelector implementation.

Using multi-select filters is a powerful technique that improves usability, flexibility, and analytical capability across both Classic and Modern UI.

If you have feedback or ideas for further enhancements – we’d love to hear from you!

You can read more on the Acumatica Community.

Subscribe To Our Newsletter

Get the latest insights on exponential technologies delivered straight to you