From 311fe150315c434b35bdc16d1765da8de3af0ce0 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Tue, 1 Dec 2020 00:47:53 +0300 Subject: [PATCH] feat: add typeahead to extensible form props --- .../extensible-form-prop.component.html | 53 +++++++++--- .../extensible-form-prop.component.ts | 85 +++++++++++++++---- 2 files changed, 113 insertions(+), 25 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.html b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.html index 60f35d636e..f3f60a56dc 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.html +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.html @@ -1,6 +1,6 @@
- + + + + +
- +
- + + + +
+ + +
+
+ - + - + - + - +
+ + + + diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts index 6b5b241924..60ae170957 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts @@ -4,14 +4,22 @@ import { ChangeDetectorRef, Component, Input, + OnChanges, Optional, SimpleChanges, SkipSelf, - OnChanges, } from '@angular/core'; -import { ControlContainer, Validators, ValidatorFn } from '@angular/forms'; +import { + ControlContainer, + FormGroup, + FormGroupDirective, + ValidatorFn, + Validators, +} from '@angular/forms'; import { NgbDateAdapter, NgbTimeAdapter } from '@ng-bootstrap/ng-bootstrap'; import { Observable, of } from 'rxjs'; +import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators'; +import snq from 'snq'; import { DateAdapter } from '../../adapters/date.adapter'; import { TimeAdapter } from '../../adapters/time.adapter'; import { ePropType } from '../../enums/props.enum'; @@ -38,6 +46,8 @@ export class ExtensibleFormPropComponent implements OnChanges { @Input() prop: FormProp; + asterisk = ''; + options$: Observable[]> = of([]); validators: ValidatorFn[] = []; @@ -46,15 +56,55 @@ export class ExtensibleFormPropComponent implements OnChanges { disabled: boolean; - constructor(public readonly cdRef: ChangeDetectorRef, public readonly track: TrackByService) {} + private readonly form: FormGroup; + + typeaheadModel: any; - get asterisk(): string { - return this.validators.some(validator => validator === Validators.required) ? '*' : ''; + setTypeaheadValue(selectedOption: ABP.Option) { + this.typeaheadModel = selectedOption || { key: null, value: null }; + const { key, value } = this.typeaheadModel; + const [keyControl, valueControl] = this.getTypeaheadControls(); + keyControl.setValue(key); + valueControl.setValue(value); + valueControl.markAsDirty(); + valueControl.markAsTouched(); } - getComponent(prop: FormProp): string { - if (prop.options && prop.type !== ePropType.MultiSelect) return 'select'; + search = (text$: Observable) => + text$ + ? text$.pipe( + debounceTime(300), + distinctUntilChanged(), + switchMap(text => this.prop.options(this.data, text)), + ) + : of([]); + + typeaheadFormatter = (option: ABP.Option) => option.key; + + get isInvalid() { + const control = this.form.get(this.prop.name); + return control.touched && control.invalid; + } + + constructor( + public readonly cdRef: ChangeDetectorRef, + public readonly track: TrackByService, + groupDirective: FormGroupDirective, + ) { + this.form = groupDirective.form; + } + private getTypeaheadControls() { + const { name } = this.prop; + const { [name + '_Text']: key, [name]: value } = this.form.controls; + return [key, value]; + } + + private setAsterisk() { + this.asterisk = this.validators.some(v => v === Validators.required) ? '*' : ''; + } + + getComponent(prop: FormProp): string { switch (prop.type) { case ePropType.Boolean: return 'checkbox'; @@ -62,14 +112,18 @@ export class ExtensibleFormPropComponent implements OnChanges { return 'date'; case ePropType.DateTime: return 'dateTime'; + case ePropType.Hidden: + return 'hidden'; + case ePropType.MultiSelect: + return 'multiselect'; case ePropType.Text: return 'textarea'; case ePropType.Time: return 'time'; - case ePropType.MultiSelect: - return 'multiselect'; + case ePropType.Typeahead: + return 'typeahead'; default: - return 'input'; + return prop.options ? 'select' : 'input'; } } @@ -92,14 +146,15 @@ export class ExtensibleFormPropComponent implements OnChanges { } ngOnChanges({ prop }: SimpleChanges) { - const options = prop.currentValue.options; - const readonly = prop.currentValue.readonly; - const disabled = prop.currentValue.disabled; - const validators = prop.currentValue.validators; + const currentProp = snq(() => prop.currentValue); + const { options, readonly, disabled, validators } = currentProp || {}; if (options) this.options$ = options(this.data); if (readonly) this.readonly = readonly(this.data); if (disabled) this.disabled = disabled(this.data); - if (validators) this.validators = validators(this.data); + if (validators) { + this.validators = validators(this.data); + this.setAsterisk(); + } } }