File

src/app/core/filter/filters/filters.ts

Index

Properties
Methods

Constructor

Protected constructor(name: string, label: string)
Parameters :
Name Type Optional
name string No
label string No

Properties

component
Type : Type<any>
Default value : ListFilterComponent

The component used to display filter option to the user.

Public label
Type : string
Default value : name
Public name
Type : string
selectedOptionChange
Default value : new EventEmitter<string[]>()

Triggered when this filter changes value (e.g. when the user selects a new value in a FilterComponent).

This is part of the filter object because dynamic filter components can't expose @Outputs

Public selectedOptionValues
Type : string[]
Default value : []

Methods

Abstract getFilter
getFilter()
Returns : DataFilter<T>
import { Entity } from "../../entity/model/entity";
import { MongoQuery } from "@casl/ability";
import { ListFilterComponent } from "../list-filter/list-filter.component";
import { EventEmitter, Type } from "@angular/core";

/**
 * This filter can be used to filter an array of entities.
 * It has to follow the MongoDB Query Syntax {@link https://www.mongodb.com/docs/manual/reference/operator/query/}.
 *
 * The filter is parsed using ucast {@link https://github.com/stalniy/ucast/tree/master/packages/mongo2js}
 */
export type DataFilter<T> = MongoQuery<T> | {};

export abstract class Filter<T extends Entity> {
  /**
   * The component used to display filter option to the user.
   */
  component: Type<any> = ListFilterComponent;

  public selectedOptionValues: string[] = [];

  /**
   * Triggered when this filter changes value
   * (e.g. when the user selects a new value in a FilterComponent).
   *
   * This is part of the filter object because dynamic filter components can't expose @Outputs
   */
  selectedOptionChange = new EventEmitter<string[]>();

  protected constructor(
    public name: string,
    public label: string = name,
  ) {}

  abstract getFilter(): DataFilter<T>;
}

/**
 * Generic configuration for a filter with different selectable {@link FilterSelectionOption} options.
 *
 * This is a reusable format for any kind of dropdown or selection component that offers the user a choice
 * to narrow down a list of data items.
 * As the filter function is provided as part of each {@link FilterSelectionOption}
 * an instance of this FilterSelection class can manage all filter selection logic.
 */
export class SelectableFilter<T extends Entity> extends Filter<T> {
  /**
   * Generate filter options dynamically from the given value to be matched.
   *
   * This is a utility function to make it easier to generate {@link FilterSelectionOption}s for standard cases
   * if you simply want each option to filter items having the given attribute matching different values.
   * If you have more sophisticated filtering needs, use the constructor to set {@link FilterSelectionOption}s that
   * you created yourself.
   *
   * @param valuesToMatchAsOptions An array of values to be matched.
   *        A separate FilterSelectionOption is created for each value with a filter
   *        that is true of a data item's property exactly matches that value.
   * @param attributeName The name of the property of a data item that is compared to the value in the filter function.
   */
  public static generateOptions<T extends Entity>(
    valuesToMatchAsOptions: (string | number)[],
    attributeName: string,
  ): FilterSelectionOption<T>[] {
    let keys = new Set();
    return (
      valuesToMatchAsOptions
        .filter((k) => !!k)
        .map((k) => ({
          key: k.toString().toLowerCase(),
          label: k.toString(),
          filter: { [attributeName]: k } as DataFilter<T>,
        }))
        // remove duplicates:
        .filter((value) => !keys.has(value.key) && keys.add(value.key))
    );
  }

  /**
   * Create a FilterSelection with different options to be selected.
   * @param name The name or id describing this filter
   * @param options An array of different filtering variants to chose between
   * @param label The user-friendly label describing this filter-selection
   * (optional, defaults to the name of the selection)
   */
  constructor(
    public override name: string,
    public options: FilterSelectionOption<T>[],
    public override label: string = name,
  ) {
    super(name, label);
    this.selectedOptionValues = [];
  }

  /**
   * Get the full filter option by its key.
   * @param key The identifier of the requested option
   */
  getOption(key: string): FilterSelectionOption<T> | undefined {
    return this.options.find((option: FilterSelectionOption<T>): boolean => {
      return option.key === key;
    });
  }

  /**
   * Get the filter query for the given option.
   * If the given key is undefined or invalid, the returned filter matches any elements.
   */
  public getFilter(): DataFilter<T> {
    const filters: DataFilter<T>[] = this.selectedOptionValues
      .map((value: string) => this.getOption(value))
      .filter((value: FilterSelectionOption<T>) => value !== undefined)
      .map((previousValue: FilterSelectionOption<T>) => {
        return previousValue.filter as DataFilter<T>;
      });

    if (filters.length === 0) {
      return {} as DataFilter<T>;
    }
    return {
      $or: [...filters],
    } as unknown as DataFilter<T>;
  }
}

/**
 * Represents one specific option to filter data in a certain way.
 * used by {@link SelectableFilter}
 */
export interface FilterSelectionOption<T> {
  /** identifier for this option in the parent FilterSelection instance */
  key: string;

  /** label displayed for this option to the user in the UI */
  label: string;

  /** Optional color */
  color?: string;

  /**
   * The filter query which should be used if this filter is selected
   */
  filter: DataFilter<T>;
}

results matching ""

    No results matching ""