src/app/core/basic-datatypes/date/date-range-filter/date-range-filter.component.ts

Metadata

Relationships

Depends on

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor()

Inputs

filterConfig
Type : DateFilter<T>

Outputs

dateRangeChange
Type : { from: Date | null; to: Date | null }

Methods

dateChangedManually
dateChangedManually()
Returns : void
openDialog
openDialog(e: Event)
Parameters :
Name Type Optional
e Event No
Returns : void
resetNoDateFilter
resetNoDateFilter()
Returns : void

Properties

Readonly fromDate
Type : unknown
Default value : signal<Date | null>(null)
Readonly isAnyDateFilterActive
Type : unknown
Default value : computed( () => this.selectedOptionValues().length > 0, )
Readonly isNoDateFilterActive
Type : unknown
Default value : computed( () => this.selectedOptionValues()[0] === EMPTY_FILTER_OPTION_KEY, )
Readonly toDate
Type : unknown
Default value : signal<Date | null>(null)
import {
  ChangeDetectionStrategy,
  Component,
  computed,
  effect,
  inject,
  input,
  output,
  signal,
} from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { Entity } from "../../../entity/model/entity";
import { DateRangeFilterPanelComponent } from "./date-range-filter-panel/date-range-filter-panel.component";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatDatepickerModule } from "@angular/material/datepicker";
import { MatButtonModule } from "@angular/material/button";
import { MatTooltipModule } from "@angular/material/tooltip";
import { FormsModule } from "@angular/forms";
import { FaIconComponent } from "@fortawesome/angular-fontawesome";
import { dateToString, isValidDate } from "../../../../utils/utils";
import { DateFilter } from "app/core/filter/filters/dateFilter";
import { EMPTY_FILTER_OPTION_KEY } from "app/core/filter/filters/filters";

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-date-range-filter",
  templateUrl: "./date-range-filter.component.html",
  styleUrls: ["./date-range-filter.component.scss"],
  imports: [
    MatFormFieldModule,
    MatDatepickerModule,
    MatButtonModule,
    MatTooltipModule,
    FormsModule,
    FaIconComponent,
  ],
})
export class DateRangeFilterComponent<T extends Entity> {
  private dialog = inject(MatDialog);
  private readonly selectedOptionValues = signal<string[]>([]);

  readonly fromDate = signal<Date | null>(null);
  readonly toDate = signal<Date | null>(null);

  filterConfig = input<DateFilter<T>>();
  dateRangeChange = output<{ from: Date | null; to: Date | null }>();
  readonly isNoDateFilterActive = computed(
    () => this.selectedOptionValues()[0] === EMPTY_FILTER_OPTION_KEY,
  );
  readonly isAnyDateFilterActive = computed(
    () => this.selectedOptionValues().length > 0,
  );
  private readonly selectedRange = computed(() => {
    const filterConfig = this.filterConfig();
    this.selectedOptionValues(); // tracked to re-run when values change
    if (!filterConfig) {
      return { from: null as Date | null, to: null as Date | null };
    }
    const range = filterConfig.getDateRange();
    return { from: range.start ?? null, to: range.end ?? null };
  });

  constructor() {
    effect((onCleanup) => {
      const filterConfig = this.filterConfig();
      if (!filterConfig) return;

      this.selectedOptionValues.set([
        ...(filterConfig.selectedOptionValues ?? []),
      ]);

      const sub = filterConfig.selectedOptionChange.subscribe((values) => {
        this.selectedOptionValues.set([...(values ?? [])]);
      });
      onCleanup(() => sub.unsubscribe());
    });

    effect(() => {
      const range = this.selectedRange();
      this.fromDate.set(range.from);
      this.toDate.set(range.to);
      this.dateRangeChange.emit({ from: range.from, to: range.to });
    });
  }

  dateChangedManually() {
    const filterConfig = this.filterConfig();
    if (!filterConfig) return;
    const from = this.fromDate();
    const to = this.toDate();
    filterConfig.selectedOptionValues = [
      isValidDate(from) ? dateToString(from) : "",
      isValidDate(to) ? dateToString(to) : "",
    ];
    filterConfig.selectedOptionChange.emit(filterConfig.selectedOptionValues);
  }

  resetNoDateFilter(): void {
    const filterConfig = this.filterConfig();
    if (!filterConfig) return;
    filterConfig.selectedOptionValues = [];
    filterConfig.selectedOptionChange.emit(filterConfig.selectedOptionValues);
  }

  openDialog(e: Event) {
    e.stopPropagation();
    this.dialog
      .open(DateRangeFilterPanelComponent, {
        width: "600px",
        minWidth: "400px",
        data: {
          selectedOptionValues: this.filterConfig()?.selectedOptionValues,
          selectedOption: this.filterConfig()?.getSelectedOption(),
          dateRange: this.filterConfig()?.getDateRange(),
          rangeOptions: this.filterConfig()?.rangeOptions,
        },
      })
      .afterClosed()
      .subscribe((result) => {
        if (!result) return;
        const filterConfig = this.filterConfig();
        if (!filterConfig) return;
        filterConfig.selectedOptionValues = result.selectedOptionValues;
        filterConfig.selectedOptionChange.emit(
          filterConfig.selectedOptionValues,
        );
      });
  }
}
<mat-form-field appearance="fill" floatLabel="always" class="full-width">
  <mat-label>{{ filterConfig()?.label || filterConfig()?.name }}</mat-label>

  <mat-date-range-input [class.hidden]="isNoDateFilterActive()">
    <input
      matStartDate
      (dateChange)="dateChangedManually()"
      [ngModel]="fromDate()"
      (ngModelChange)="fromDate.set($event)"
      i18n-placeholder="Date selection"
      placeholder="Start date"
    />
    <input
      matEndDate
      (dateChange)="dateChangedManually()"
      [ngModel]="toDate()"
      (ngModelChange)="toDate.set($event)"
      i18n-placeholder="Date selection"
      placeholder="End date"
    />
  </mat-date-range-input>

  @if (isNoDateFilterActive()) {
    <span i18n>not defined</span>
  }

  <mat-datepicker-toggle
    matSuffix
    (click)="openDialog($event)"
  ></mat-datepicker-toggle>
  @if (isAnyDateFilterActive()) {
    <button
      matSuffix
      mat-icon-button
      type="button"
      class="date-reset-button"
      i18n-aria-label
      aria-label="Reset date filter"
      matTooltip="Clear date filter"
      i18n-matTooltip="Tooltip: clears the date filter"
      (click)="resetNoDateFilter()"
    >
      <fa-icon icon="xmark"></fa-icon>
    </button>
  }
</mat-form-field>

./date-range-filter.component.scss

.date-reset-button {
  color: #000;
}

.hidden {
  display: none !important;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""