|
filterConfig
|
Type : DateFilter<T>
|
|
|
Outputs
|
dateRangeChange
|
Type : { from: Date | null; to: Date | null }
|
|
|
Methods
|
dateChangedManually
|
dateChangedManually()
|
|
|
|
|
|
openDialog
|
openDialog(e: Event)
|
|
|
Parameters :
| Name |
Type |
Optional |
| e |
Event
|
No
|
|
|
resetNoDateFilter
|
resetNoDateFilter()
|
|
|
|
|
|
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-reset-button {
color: #000;
}
.hidden {
display: none !important;
}
Legend
Html element with directive