Simple popup filter

This commit is contained in:
Adina Țeudan 2024-06-17 12:18:25 +03:00
parent 748cce4032
commit aec5da15df
4 changed files with 145 additions and 0 deletions

View File

@ -11,3 +11,4 @@ export * from './models/nested-filter.model';
export * from './popup-filter/popup-filter.component';
export * from './quick-filters/quick-filters.component';
export * from './simple-popup-filter/simple-popup-filter.component';

View File

@ -0,0 +1,53 @@
<ng-container *ngIf="icon">
<iqser-icon-button
[attr.aria-expanded]="expanded()"
[class.disabled]="disabled()"
[disabled]="disabled()"
[icon]="icon()"
[label]="label()"
[matMenuTriggerFor]="filterMenu"
[showDot]="hasActiveFilters()"
></iqser-icon-button>
</ng-container>
<ng-container *ngIf="!icon">
<iqser-chevron-button
[attr.aria-expanded]="expanded()"
[class.disabled]="disabled"
[disabled]="disabled()"
[label]="label()"
[matMenuTriggerFor]="filterMenu"
[showDot]="hasActiveFilters()"
></iqser-chevron-button>
</ng-container>
<mat-menu #filterMenu="matMenu" (closed)="expanded.set(false)" xPosition="before">
<div iqserStopPropagation>
<ng-template matMenuContent>
<div class="input-wrapper">
<iqser-input-with-action
[value]="searchValue()"
(valueChange)="searchValue.set($event)"
[placeholder]="filterPlaceholder()"
[width]="'full'"
></iqser-input-with-action>
</div>
<div class="filter-menu-header">
<div translate="filter-menu.label" class="all-caps-label"></div>
<div class="actions">
<div (click)="_selectAll()" class="all-caps-label primary pointer" iqserStopPropagation translate="actions.all"></div>
<div (click)="_clear()" class="all-caps-label primary pointer" iqserStopPropagation translate="actions.none"></div>
</div>
</div>
<div class="filter-content">
<div mat-menu-item *ngFor="let option of displayedOptions()" (click)="_filterCheckboxClicked(option)">
<mat-checkbox [checked]="selectedOptions().includes(option)" class="filter-menu-checkbox">
{{ option.label }}
</mat-checkbox>
</div>
</div>
</ng-template>
</div>
</mat-menu>

View File

@ -0,0 +1,24 @@
@use 'common-mixins';
.filter-menu-options,
.filter-menu-header {
display: flex;
justify-content: space-between;
padding: 8px 16px 16px 16px;
min-width: var(--filter-card-min-width);
.actions {
display: flex;
gap: 8px;
}
}
.input-wrapper {
padding: 0 8px 8px 8px;
}
.filter-content {
max-height: 300px;
overflow: auto;
@include common-mixins.scroll-bar;
}

View File

@ -0,0 +1,67 @@
import { Component, computed, input, output, signal, untracked } from '@angular/core';
import { MatMenuModule } from '@angular/material/menu';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatCheckbox } from '@angular/material/checkbox';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { ChevronButtonComponent, IconButtonComponent } from '../../buttons';
import { StopPropagationDirective } from '../../directives';
import { InputWithActionComponent } from '../../inputs';
@Component({
selector: 'iqser-simple-popup-filter',
templateUrl: './simple-popup-filter.component.html',
styleUrls: ['./simple-popup-filter.component.scss'],
standalone: true,
imports: [
CommonModule,
MatMenuModule,
IconButtonComponent,
ChevronButtonComponent,
StopPropagationDirective,
InputWithActionComponent,
TranslateModule,
MatCheckbox,
IconButtonComponent,
ChevronButtonComponent,
],
})
export class SimplePopupFilterComponent<T extends { label: string }> {
options = input.required<T[]>();
icon = input<string>();
label = input<string>();
filterPlaceholder = input.required<string>();
disabled = input<boolean>(false);
selectionChanged = output<T[]>();
readonly expanded = signal(false);
readonly selectedOptions = signal<T[]>([]);
readonly hasActiveFilters = computed(() => this.selectedOptions().length > 0);
readonly searchValue = signal('');
readonly displayedOptions = computed(() =>
this.options().filter(option => option.label.toLowerCase().includes(this.searchValue().toLowerCase())),
);
constructor() {
toObservable(this.selectedOptions)
.pipe(takeUntilDestroyed())
// eslint-disable-next-line rxjs/no-ignored-subscription
.subscribe(() => this.selectionChanged.emit(this.selectedOptions()));
}
protected _selectAll(): void {
this.selectedOptions.set(untracked(this.options));
}
protected _clear(): void {
this.selectedOptions.set([]);
}
protected _filterCheckboxClicked(option: T): void {
if (this.selectedOptions().includes(option)) {
this.selectedOptions.set(this.selectedOptions().filter(selectedOption => selectedOption !== option));
} else {
this.selectedOptions.set([...this.selectedOptions(), option]);
}
}
}