fix(shared-filter, reward-catalog): Added Branch Filter Toggle to Reward HSC View, Adjusted Controls Panel Filter Styling and Layout to fix mobile issues and added spacing to order-by-toolbar Refs: #5514, #5475
ISA Filter Library
A powerful and flexible filtering library for Angular applications that provides a complete solution for implementing filters, search functionality, and sorting capabilities.
Overview
The ISA Filter Library is designed to help developers quickly implement advanced filtering capabilities in their Angular applications. It provides a set of reusable components, schemas, and services to handle various types of filters, user inputs, and sorting options.
Features
- Multiple Filter Types: Support for text search, checkboxes, date ranges, and more
- Flexible Architecture: Easily extendable to support custom filter types
- Modern Angular Patterns: Built with Angular signals for reactive state management
- Schema-based Validation: Type-safe filter models with zod schema validation
- Responsive Design: Mobile-friendly filter UI components
- Declarative API: Simple and intuitive API for configuring filters
- Sorting Capabilities: Built-in support for sorting data by various criteria
- TypeScript Support: Fully typed for excellent developer experience
Installation
The library is part of the ISA Frontend monorepo and can be imported using:
import { ... } from '@isa/shared/filter';
Core Concepts
Filter Service
The FilterService is the central component of the library, responsible for managing filter state and providing methods to update and query filter values.
// Example of using FilterService
export class MyComponent {
constructor(private filterService: FilterService) {}
applyFilters() {
// Apply filters and get the query
const query = this.filterService.getQuery();
// Use the query to fetch filtered data
}
resetFilters() {
this.filterService.reset();
}
}
Filter Types
The library supports several filter input types:
- Text Filters (
InputType.Text): For search queries and text-based filtering - Checkbox Filters (
InputType.Checkbox): For multi-select options with optional selection limits - Date Range Filters (
InputType.DateRange): For time-based filtering
Query Settings
Filter configurations are defined using the QuerySettings interface, which includes filter groups, input fields, and sort options.
// Example QuerySettings configuration
const settings: QuerySettings = {
filter: [
{
group: 'products',
label: 'Product Filters',
input: [
{
key: 'category',
label: 'Category',
type: InputType.Checkbox,
options: {
max: 3, // Optional: Limit selection to 3 items
values: [
{ label: 'Electronics', value: 'electronics' },
{ label: 'Clothing', value: 'clothing' },
{ label: 'Books', value: 'books' },
{ label: 'Sports', value: 'sports' },
],
},
},
],
},
],
input: [],
orderBy: [
{ by: 'price', label: 'Price (Low to High)', desc: false },
{ by: 'price', label: 'Price (High to Low)', desc: true },
],
};
Components
Filter Menu
The FilterMenuComponent provides a UI for displaying and interacting with filters:
<filter-filter-menu (applied)="onApplyFilters()" (reseted)="onResetFilters()">
</filter-filter-menu>
Order By Toolbar
The OrderByToolbarComponent allows users to sort data based on different criteria:
<filter-order-by-toolbar [commitOnToggle]="true" (toggled)="onSortChanged()">
</filter-order-by-toolbar>
Input Components
The library includes specialized components for different input types:
CheckboxInputComponent: For multi-select options with optional selection limitsDatepickerRangeInputComponent: For date range selectionSearchBarInputComponent: For text-based search
Input Renderer
The InputRendererComponent dynamically renders the appropriate input component based on the filter type:
<filter-input-renderer [filterInput]="myFilterInput"></filter-input-renderer>
Usage Examples
Basic Filter Implementation
// Import filter library
import { QuerySettings, InputType, provideFilter } from '@isa/shared/filter';
// Define filter settings
const settings: QuerySettings = {
filter: [
{
group: 'filter',
label: 'Filters',
input: [
{
key: 'status',
label: 'Status',
type: InputType.Checkbox,
options: {
max: 2, // Allow up to 2 status selections
values: [
{ label: 'Active', value: 'active' },
{ label: 'Inactive', value: 'inactive' },
{ label: 'Pending', value: 'pending' },
],
},
},
],
},
],
input: [],
orderBy: [
{ by: 'name', label: 'Name (A-Z)', desc: false },
{ by: 'name', label: 'Name (Z-A)', desc: true },
],
};
// Provide filter in component/module
@Component({
// ...
providers: [provideFilter(settings)],
})
export class MyFilterComponent {
// ...
}
Implementing Filter Logic
@Component({
// ...
})
export class ProductListComponent {
constructor(private filterService: FilterService) {}
products = computed(() => {
const query = this.filterService.getQuery();
return this.applyFilters(this.allProducts, query);
});
private applyFilters(products: Product[], query: Query): Product[] {
// Implement filtering logic based on query
return filteredProducts;
}
onApplyFilters() {
// Trigger data refresh or update
this.filterService.commit();
}
}
Maximum Options for Checkbox Filters
Checkbox filters support an optional max property to limit the number of selections users can make:
// Configuration with maximum options
{
key: 'tags',
label: 'Tags',
type: InputType.Checkbox,
options: {
max: 5, // Users can select up to 5 tags
values: [
{ label: 'JavaScript', value: 'js' },
{ label: 'TypeScript', value: 'ts' },
{ label: 'Angular', value: 'angular' },
{ label: 'React', value: 'react' },
{ label: 'Vue', value: 'vue' },
{ label: 'Node.js', value: 'node' },
{ label: 'Python', value: 'python' },
],
},
}
Behavior with Maximum Options:
- FIFO Strategy: When the limit is exceeded, the oldest selections are automatically removed
- UI Enhancement: The "Select All" control is hidden when
maxis configured to prevent user confusion - Automatic Enforcement: The filter service handles limit enforcement transparently
Example with FIFO Behavior:
// Starting state: [] (empty)
// User selects: ['js']
// User selects: ['js', 'ts']
// User selects: ['js', 'ts', 'angular']
// User selects: ['js', 'ts', 'angular', 'react']
// User selects: ['js', 'ts', 'angular', 'react', 'vue']
// User selects 'node' -> ['ts', 'angular', 'react', 'vue', 'node'] (oldest 'js' removed)
} }
## Schema Validation
The library uses Zod schemas to validate filter configurations and user inputs:
```typescript
// Example of a filter schema
export const CheckboxFilterInputSchema = CheckboxFilterInputBaseSchema.extend({
options: z
.object({
values: z.array(CheckboxFilterInputOptionSchema).optional(),
max: z.number().optional(),
})
.optional(),
selected: z.array(z.string()).default([]),
type: z.literal(InputType.Checkbox),
});
Architecture
The Filter library is organized into several key modules:
Core Module
- Schemas: Type definitions and validation using Zod
- Mappings: Functions to transform between API and UI models
- Service: The
FilterServicefor state management - Tokens: Injection tokens for DI configuration
Inputs Module
- CheckboxInput: Multi-select options component with configurable selection limits
- DatepickerRangeInput: Date range selection component
- SearchBarInput: Text-based search component
- InputRenderer: Dynamic component renderer
Menus Module
- FilterMenu: UI for displaying and interacting with filters
- InputMenu: Specialized component for input configuration
Actions Module
Components for filter operations (apply, reset, etc.)
Order By Module
Components for sorting data based on different criteria
Best Practices
- Group Related Filters: Use filter groups to organize related filters together
- Provide Clear Labels: Use descriptive labels for filters and options
- Use Appropriate Filter Types: Choose the right filter type for the data being filtered
- Handle Filter State: Properly manage filter state, especially for URL synchronization
- Combine with NgRx: For complex applications, consider using the library with NgRx for state management
Running unit tests
Run nx test shared-filter to execute the unit tests.