Skip to content

@memberjunction/ng-filter-builder

A modern, intuitive Angular filter builder component for creating complex boolean filter expressions. Outputs portable, Kendo-compatible CompositeFilterDescriptor JSON for seamless integration with MemberJunction views and grids.

Terminal window
npm install @memberjunction/ng-filter-builder

The Filter Builder provides a visual interface for constructing nested AND/OR filter expressions against entity fields. It supports multiple field types (string, number, boolean, date, lookup), nested groups up to a configurable depth, and generates a human-readable summary of the active filter.

graph TD
    A["FilterBuilderComponent"] --> B["FilterGroupComponent"]
    B --> C["FilterRuleComponent"]
    B --> D["FilterRuleComponent"]
    B --> E["Nested FilterGroupComponent"]
    E --> F["FilterRuleComponent"]
    A --> G["CompositeFilterDescriptor JSON"]

    style A fill:#2d6a9f,stroke:#1a4971,color:#fff
    style B fill:#7c5295,stroke:#563a6b,color:#fff
    style C fill:#2d8659,stroke:#1a5c3a,color:#fff
    style D fill:#2d8659,stroke:#1a5c3a,color:#fff
    style E fill:#7c5295,stroke:#563a6b,color:#fff
    style F fill:#2d8659,stroke:#1a5c3a,color:#fff
    style G fill:#b8762f,stroke:#8a5722,color:#fff
import { FilterBuilderModule } from '@memberjunction/ng-filter-builder';
@NgModule({
imports: [FilterBuilderModule]
})
export class YourModule {}
<mj-filter-builder
[fields]="filterFields"
[filter]="currentFilter"
(filterChange)="onFilterChange($event)">
</mj-filter-builder>

Pass sources and the builder always writes SourceKey.FieldName. One source still prefixes. Several sources: two-pane field picker (source list | fields). Bare names in existing JSON still load.

<mj-filter-builder
[sources]="[
{ key: 'Order', label: 'Order', fields: orderFields },
{ key: 'BillToOrganization', label: 'Bill-to organization', fields: orgFields }
]"
[filter]="filter"
[showSummary]="true"
(filterChange)="onChange($event)">
</mj-filter-builder>

JSON: { "field": "BillToOrganization.Type", "operator": "eq", "value": "Member" }.

Evaluate and summarize without Angular:

import { CompositeFilter } from '@memberjunction/core';
const cf = CompositeFilter.FromDescriptor(filter);
cf.Evaluate({ BillToOrganization: org, Order: header });
cf.SummaryText({ SourceLabels: { BillToOrganization: 'Bill-to organization' } });

See Filter Builder & Evaluation.

import { FilterFieldInfo } from '@memberjunction/ng-filter-builder';
filterFields: FilterFieldInfo[] = [
{ name: 'Name', displayName: 'Name', type: 'string', description: 'Full display name of the contact' },
{ name: 'Age', displayName: 'Age', type: 'number', description: 'Age in years' },
{ name: 'IsActive', displayName: 'Active', type: 'boolean', description: 'Whether the record is currently active' },
{ name: 'CreatedAt', displayName: 'Created Date', type: 'date' },
{ name: 'CategoryID', displayName: 'Category', type: 'lookup', lookupEntityName: 'Categories' }
];

Rich Searchable Field Picker (description & Viewport Flip-Up)

Section titled “Rich Searchable Field Picker (description & Viewport Flip-Up)”

FilterRuleComponent intentionally uses a purpose-built, fixed-positioned searchable field picker (role="listbox" / role="option") instead of a native <select> or single-line <mj-combobox>:

  • Multi-Line Field Descriptions: When FilterFieldInfo.description is populated (for example from EntityField.Description), each option renders a secondary description line alongside the field’s display name and data-type badge.
  • Two-Pane Multi-Entity Source Picker: When sources has multiple entities, the dropdown renders a two-pane layout (entity source list on the left, searchable field list on the right).
  • Automatic Viewport Flip-Up (dropUp): Measures available viewport space below and above the trigger (accounting for transformed ancestor containers) and automatically opens upward when near the bottom of the screen.
  • Contained Keyboard Navigation: Supports ArrowDown, ArrowUp, Enter, and Escape (closing only the open field menu via event.stopPropagation() + event.preventDefault() so parent modal dialogs remain open).
<mj-filter-builder
[fields]="filterFields"
[config]="{
maxDepth: 3,
allowGroups: true,
showClearButton: true,
showApplyButton: false,
applyOnChange: true
}"
[showSummary]="true"
[disabled]="false"
(filterChange)="onFilterChange($event)"
(apply)="onApply($event)"
(clear)="onClear()">
</mj-filter-builder>
ComponentSelectorPurpose
FilterBuilderComponentmj-filter-builderTop-level container with config, summary, and clear/apply buttons
FilterGroupComponentinternalRenders a group of rules combined by AND/OR logic
FilterRuleComponentinternalRenders a single filter rule (field, operator, value)
TypeOperators
Stringcontains, does not contain, equals, not equals, starts with, ends with, is empty, is not empty
Numberequals, not equals, greater than, greater/equal, less than, less/equal, is empty, is not empty
Booleanis, is not, is empty, is not empty
Dateequals, not equals, is after, is on or after, is before, is on or before, is empty, is not empty
Lookupequals, not equals, contains, does not contain, starts with, ends with, is empty, is not empty
  • FilterOperator — Union type of all operator strings
  • FilterLogic — 'and' | 'or'
  • FilterDescriptor — Single filter condition
  • CompositeFilterDescriptor — Group of filters with AND/OR logic
  • FilterFieldInfo — Field metadata for the builder
  • FilterBuilderConfig — Configuration options
  • FilterValueOption — Value option for dropdown fields
  • CreateEmptyFilter() — Creates a new empty CompositeFilterDescriptor
  • CreateFilterRule(field, type) — Creates a new filter rule with defaults
  • IsCompositeFilter(filter) — Type guard for composite filters
  • IsSimpleFilter(filter) — Type guard for simple filter descriptors
  • GetOperatorsForType(type) — Returns available operators for a field type
  • OperatorRequiresValue(operator) — Checks if an operator needs a value input