diff --git a/package.json b/package.json index 66739c82a..2f52cb878 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "ionicons": "5.5.4", "leaflet": "^1.7.1", "meriyah": "^4.2.0", + "ngx-mat-select-search": "^7.0.5", "numbro": "^2.3.6", "pdfmake": "^0.2.4", "rxjs": "^7.5.0", @@ -125,4 +126,4 @@ "typescript": "~4.8.4", "unique-names-generator": "^4.7.1" } -} \ No newline at end of file +} diff --git a/projects/core/package.json b/projects/core/package.json index 7e2563eef..0e77e4e0b 100644 --- a/projects/core/package.json +++ b/projects/core/package.json @@ -29,6 +29,7 @@ "flag-icon-css": "0.0.0-FLAG-ICON-CSS", "leaflet": "0.0.0-LEAFLET", "meriyah": "0.0.0-MERIYAH", + "ngx-mat-select-search": "0.0.0-NGX-MAT-SELECT-SEARCH", "numbro": "0.0.0-NUMBRO", "pdfmake": "0.0.0-PDFMAKE", "svg-pan-zoom": "0.0.0-SVG-PAN-ZOOM", diff --git a/projects/material/forms/src/forms-module.ts b/projects/material/forms/src/forms-module.ts index a0d27087d..c8d9ab2f3 100644 --- a/projects/material/forms/src/forms-module.ts +++ b/projects/material/forms/src/forms-module.ts @@ -69,6 +69,7 @@ import {AjfTextFieldComponent} from './text-field'; import {AjfTimeFieldComponent} from './time-field'; import {AjfVideoUrlFieldComponent} from './video-url-field'; import {AjfWarningAlertService} from './warning-alert-service'; +import {NgxMatSelectSearchModule} from 'ngx-mat-select-search'; import {AjfSignatureModule} from '@ajf/material/signature'; @NgModule({ @@ -101,6 +102,7 @@ import {AjfSignatureModule} from '@ajf/material/signature'; ReactiveFormsModule, TextFieldModule, MatSliderModule, + NgxMatSelectSearchModule, ], declarations: [ AjfBarcodeFieldComponent, diff --git a/projects/material/forms/src/multiple-choice-field.html b/projects/material/forms/src/multiple-choice-field.html index a7f6ddac4..7afe3ca23 100644 --- a/projects/material/forms/src/multiple-choice-field.html +++ b/projects/material/forms/src/multiple-choice-field.html @@ -1,8 +1,15 @@ - + + + + + {{ choice.label | transloco }} @@ -11,8 +18,7 @@ - + {{ choice.label | transloco }} diff --git a/projects/material/forms/src/multiple-choice-field.ts b/projects/material/forms/src/multiple-choice-field.ts index a00dc5539..f3e62e74e 100644 --- a/projects/material/forms/src/multiple-choice-field.ts +++ b/projects/material/forms/src/multiple-choice-field.ts @@ -23,17 +23,22 @@ import { AJF_SEARCH_ALERT_THRESHOLD, AJF_WARNING_ALERT_SERVICE, + AjfChoice, AjfFieldWithChoicesComponent, AjfFormRendererService, } from '@ajf/core/forms'; import { + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, + OnDestroy, Optional, ViewEncapsulation, } from '@angular/core'; +import {FormControl} from '@angular/forms'; +import {Subscription} from 'rxjs'; import {AjfWarningAlertService} from './warning-alert-service'; @@ -43,7 +48,14 @@ import {AjfWarningAlertService} from './warning-alert-service'; changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, }) -export class AjfMultipleChoiceFieldComponent extends AjfFieldWithChoicesComponent { +export class AjfMultipleChoiceFieldComponent + extends AjfFieldWithChoicesComponent implements AfterViewInit, OnDestroy { + + readonly searchFilterCtrl = new FormControl(''); + private searchFilterSub: Subscription; + + filteredChoices: AjfChoice[] = []; + constructor( cdr: ChangeDetectorRef, service: AjfFormRendererService, @@ -51,5 +63,29 @@ export class AjfMultipleChoiceFieldComponent extends AjfFieldWithChoicesCompo @Optional() @Inject(AJF_SEARCH_ALERT_THRESHOLD) searchThreshold: number, ) { super(cdr, service, was, searchThreshold); + + this.searchFilterSub = this.searchFilterCtrl.valueChanges.subscribe(() => { + this.filterChoices(); + }); + } + + ngAfterViewInit(): void { + this.filteredChoices = this.instance?.filteredChoices || []; + } + + private filterChoices() { + const choices = this.instance?.filteredChoices || []; + let search = this.searchFilterCtrl.value; + if (!search) { + this.filteredChoices = choices; + return; + } + search = search.toLowerCase(); + this.filteredChoices = choices.filter(c => c.label.toLowerCase().includes(search!)); + } + + override ngOnDestroy(): void { + super.ngOnDestroy(); + this.searchFilterSub.unsubscribe(); } } diff --git a/projects/material/forms/src/single-choice-field.html b/projects/material/forms/src/single-choice-field.html index 317af6cea..40a514d49 100644 --- a/projects/material/forms/src/single-choice-field.html +++ b/projects/material/forms/src/single-choice-field.html @@ -1,8 +1,15 @@ - + + + + + {{ choice.label | transloco }} @@ -12,8 +19,7 @@ - + {{ choice.label | transloco }} diff --git a/projects/material/forms/src/single-choice-field.ts b/projects/material/forms/src/single-choice-field.ts index f149ff285..381c2dd01 100644 --- a/projects/material/forms/src/single-choice-field.ts +++ b/projects/material/forms/src/single-choice-field.ts @@ -23,17 +23,22 @@ import { AJF_SEARCH_ALERT_THRESHOLD, AJF_WARNING_ALERT_SERVICE, + AjfChoice, AjfFieldWithChoicesComponent, AjfFormRendererService, } from '@ajf/core/forms'; import { + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, + OnDestroy, Optional, ViewEncapsulation, } from '@angular/core'; +import {FormControl} from '@angular/forms'; +import {Subscription} from 'rxjs'; import {AjfWarningAlertService} from './warning-alert-service'; @@ -43,7 +48,14 @@ import {AjfWarningAlertService} from './warning-alert-service'; changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, }) -export class AjfSingleChoiceFieldComponent extends AjfFieldWithChoicesComponent { +export class AjfSingleChoiceFieldComponent + extends AjfFieldWithChoicesComponent implements AfterViewInit, OnDestroy { + + readonly searchFilterCtrl = new FormControl(''); + private searchFilterSub: Subscription; + + filteredChoices: AjfChoice[] = []; + constructor( cdr: ChangeDetectorRef, service: AjfFormRendererService, @@ -51,5 +63,29 @@ export class AjfSingleChoiceFieldComponent extends AjfFieldWithChoicesCompone @Optional() @Inject(AJF_SEARCH_ALERT_THRESHOLD) searchThreshold: number, ) { super(cdr, service, was, searchThreshold); + + this.searchFilterSub = this.searchFilterCtrl.valueChanges.subscribe(() => { + this.filterChoices(); + }); + } + + ngAfterViewInit(): void { + this.filteredChoices = this.instance?.filteredChoices || []; + } + + private filterChoices() { + const choices = this.instance?.filteredChoices || []; + let search = this.searchFilterCtrl.value; + if (!search) { + this.filteredChoices = choices; + return; + } + search = search.toLowerCase(); + this.filteredChoices = choices.filter(c => c.label.toLowerCase().includes(search!)); + } + + override ngOnDestroy(): void { + super.ngOnDestroy(); + this.searchFilterSub.unsubscribe(); } } diff --git a/scripts/utils/version-replacements.mjs b/scripts/utils/version-replacements.mjs index e3c6143df..44dfb83a0 100644 --- a/scripts/utils/version-replacements.mjs +++ b/scripts/utils/version-replacements.mjs @@ -21,6 +21,7 @@ export const versionReplacements = packages => { ['flag-icon-css', 'FLAG-ICON-CSS'], ['leaflet', 'LEAFLET'], ['meriyah', 'MERIYAH'], + ['ngx-mat-select-search', 'NGX-MAT-SELECT-SEARCH'], ['numbro', 'NUMBRO'], ['pdfmake', 'PDFMAKE'], ['svg-pan-zoom', 'SVG-PAN-ZOOM'], diff --git a/yarn.lock b/yarn.lock index 6fb27536e..274399442 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8566,6 +8566,13 @@ ng-packagr@^15.0.3: optionalDependencies: esbuild "^0.16.0" +ngx-mat-select-search@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ngx-mat-select-search/-/ngx-mat-select-search-7.0.5.tgz#0468cdaeb5ea203061737edc9a3ce0efab79fa91" + integrity sha512-FRGkXhCkQ+c2B0bZnS9C1XAOukhq6QbJLsevbV3rFiV21cVgaGQ1calf6dUfEHyQdJ1CCaf+ViccY1i3WJTPdA== + dependencies: + tslib "^2.4.0" + nice-napi@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/nice-napi/-/nice-napi-1.0.2.tgz#dc0ab5a1eac20ce548802fc5686eaa6bc654927b" @@ -10826,6 +10833,11 @@ tslib@^2.0.0, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@^2.4.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"