Asymmetrik/ngx-starter

View on GitHub
src/app/common/table/filter/asy-header-list-filter/asy-header-list-filter.component.html

Summary

Maintainability
Test Coverage
<button
    class="btn btn-text dropdown-toggle dropdown-toggle-hide-caret px-2"
    type="button"
    cdkOverlayOrigin
    #trigger
    (click)="toggle()"
>
    <span
        class="filter fa-solid fa-list"
        container="body"
        ngbTooltip="Apply Filters"
        placement="bottom"
        [hidden]="isFiltered()"
    ></span>
    <span
        class="filter fa-solid fa-filter"
        container="body"
        ngbTooltip="Edit Filters"
        placement="bottom"
        [hidden]="!isFiltered()"
    ></span>
</button>

<ng-template
    cdkConnectedOverlay
    [cdkConnectedOverlayOpen]="isOpen()"
    [cdkConnectedOverlayOrigin]="trigger"
    (attach)="loadOptions()"
    (overlayOutsideClick)="isOpen.set(false)"
>
    <div class="dropdown-menu d-flex flex-column" cdkTrapFocus cdkTrapFocusAutoCapture>
        @if (showSearch() || _options.length > showSearchMinOptions()) {
            <div class="search mt-2">
                <asy-search-input
                    placeholder="Search..."
                    [search]="search"
                    (applySearch)="onSearchOptions($event)"
                />
            </div>
            <div class="divider dropdown-divider mb-0 mx-3"></div>
        }
        <div class="flex-grow-1 overflow-auto my-2">
            @if (optionsLoading()) {
                <span class="fa-solid fa-spinner fa-spin me-1"></span>Loading...
            } @else {
                @for (option of _options; track option) {
                    @if (!option.hide) {
                        <div class="form-check">
                            <input
                                class="form-check-input"
                                id="filter-{{ id }}-option-{{ option.value }}"
                                type="checkbox"
                                [(ngModel)]="option.active"
                                [ngModelOptions]="{ standalone: true }"
                                (ngModelChange)="onFilterChange()"
                            />
                            <label
                                class="form-check-label"
                                for="filter-{{ id }}-option-{{ option.value }}"
                                >{{ option.display }}</label
                            >
                        </div>
                    }
                } @empty {
                    No options found
                }
            }
        </div>
        @if (showMatch()) {
            <div class="divider dropdown-divider my-0 mx-3"></div>
            <div class="mt-2 mb-1">
                <span class="me-3">Match:</span>
                @for (operatorOption of [false, true]; track operatorOption; let i = $index) {
                    <div class="form-check form-check-inline">
                        <input
                            class="form-check-input"
                            id="operator-option-{{ i }}"
                            name="operator-option-radio"
                            type="radio"
                            [value]="operatorOption"
                            [(ngModel)]="matchAll"
                            (ngModelChange)="onFilterChange()"
                        />
                        <label class="form-check-label" for="operator-option-{{ i }}">{{
                            operatorOption ? 'All' : 'Any'
                        }}</label>
                    </div>
                }
            </div>
        }
        @if (isFiltered()) {
            <div class="divider dropdown-divider mb-0 mx-3"></div>
            <div class="mt-2">
                <button
                    class="btn btn-link px-0"
                    type="button"
                    (click)="clearFilter(); $event.stopPropagation()"
                >
                    Clear Filters
                </button>
            </div>
        }
    </div>
</ng-template>