Files
ISA-Frontend/libs/shared/filter
Nino Righi 0da9800ca0 Merged PR 1897: #5236 #4771 Abteilungsremission
- feat(remission-list): Added Tooltip and Static Toolbar
- Merge branch 'develop' into feature/5236-Remission-Abteilungsremission-Offene-Punkte
- feat(remission-list, shared-filter, ui-input-controls): enhance department filtering and UI improvements
- Merge branch 'develop' into feature/5236-Remission-Abteilungsremission-Offene-Punkte
- Merge branch 'develop' into feature/5236-Remission-Abteilungsremission-Offene-Punkte
- feat(remission-list, remission-data-access): add department capacity display functionality

#5236 #4771 Abteilungsremission
2025-07-28 19:28:14 +00:00
..

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 limits
  • DatepickerRangeInputComponent: For date range selection
  • SearchBarInputComponent: 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 max is 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 FilterService for 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

  1. Group Related Filters: Use filter groups to organize related filters together
  2. Provide Clear Labels: Use descriptive labels for filters and options
  3. Use Appropriate Filter Types: Choose the right filter type for the data being filtered
  4. Handle Filter State: Properly manage filter state, especially for URL synchronization
  5. 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.