From d321c4ffc9e9418df1c7791bf6d4948ef88376a7 Mon Sep 17 00:00:00 2001 From: Jane Sandberg Date: Tue, 25 Jun 2019 11:17:07 -0700 Subject: [PATCH 1/1] LP1831390: combobox and date-select implement ControlValueAccessor This makes both components compatible with [(ngModel)] and reactive forms. Also adds sandbox examples. Signed-off-by: Jane Sandberg Signed-off-by: Bill Erickson Signed-off-by: Galen Charlton --- .../share/combobox/combobox.component.html | 2 +- .../app/share/combobox/combobox.component.ts | 35 ++++++++++++++++-- .../date-select/date-select.component.ts | 26 +++++++++++-- .../app/staff/sandbox/sandbox.component.html | 37 ++++++++++++++++++- .../app/staff/sandbox/sandbox.component.ts | 19 ++++++++++ .../src/app/staff/sandbox/sandbox.module.ts | 2 +- 6 files changed, 112 insertions(+), 9 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html index 0a5deeeb8c..b6099fcae9 100644 --- a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html +++ b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html @@ -16,7 +16,7 @@ [ngbTypeahead]="filter" [resultTemplate]="displayTemplate" [inputFormatter]="formatDisplayString" - (click)="click$.next($event.target.value)" + (click)="onClick($event)" (blur)="onBlur()" (selectItem)="selectorChanged($event)" #instance="ngbTypeahead"/> diff --git a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts index 99206321cd..b4c85bf5e2 100644 --- a/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts +++ b/Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts @@ -3,7 +3,8 @@ * * */ -import {Component, OnInit, Input, Output, ViewChild, EventEmitter, ElementRef} from '@angular/core'; +import {Component, OnInit, Input, Output, ViewChild, EventEmitter, ElementRef, forwardRef} from '@angular/core'; +import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import {Observable, of, Subject} from 'rxjs'; import {map, tap, reduce, mergeMap, mapTo, debounceTime, distinctUntilChanged, merge, filter} from 'rxjs/operators'; import {NgbTypeahead, NgbTypeaheadSelectItemEvent} from '@ng-bootstrap/ng-bootstrap'; @@ -24,9 +25,14 @@ export interface ComboboxEntry { styles: [` .icons {margin-left:-18px} .material-icons {font-size: 16px;font-weight:bold} - `] + `], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ComboboxComponent), + multi: true + }] }) -export class ComboboxComponent implements OnInit { +export class ComboboxComponent implements ControlValueAccessor, OnInit { selected: ComboboxEntry; click$: Subject; @@ -145,9 +151,15 @@ export class ComboboxComponent implements OnInit { } } + onClick($event) { + this.registerOnTouched(); + this.click$.next($event.target.value) + } + openMe($event) { // Give the input a chance to focus then fire the click // handler to force open the typeahead + this.registerOnTouched(); this.elm.nativeElement.getElementsByTagName('input')[0].focus(); setTimeout(() => this.click$.next('')); } @@ -222,6 +234,7 @@ export class ComboboxComponent implements OnInit { // Fired by the typeahead to inform us of a change. selectorChanged(selEvent: NgbTypeaheadSelectItemEvent) { this.onChange.emit(selEvent.item); + this.propagateChange(selEvent.item); } // Adds matching async entries to the entry list @@ -286,6 +299,22 @@ export class ComboboxComponent implements OnInit { }) ); } + + writeValue(value: any) { + if (value !== undefined) { + this.startId = value; + this.startIdFiresOnChange = true; + } + } + + propagateChange = (_: any) => {}; + + registerOnChange(fn) { + this.propagateChange = fn; + } + + registerOnTouched() { } + } diff --git a/Open-ILS/src/eg2/src/app/share/date-select/date-select.component.ts b/Open-ILS/src/eg2/src/app/share/date-select/date-select.component.ts index d877300677..079c4fe715 100644 --- a/Open-ILS/src/eg2/src/app/share/date-select/date-select.component.ts +++ b/Open-ILS/src/eg2/src/app/share/date-select/date-select.component.ts @@ -1,5 +1,6 @@ -import {Component, OnInit, Input, Output, ViewChild, EventEmitter} from '@angular/core'; +import {Component, OnInit, Input, Output, ViewChild, EventEmitter, forwardRef} from '@angular/core'; import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap'; +import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; /** * RE: displaying locale dates in the input field: @@ -10,9 +11,14 @@ import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap'; @Component({ selector: 'eg-date-select', templateUrl: './date-select.component.html', - styleUrls: ['date-select.component.css'] + styleUrls: ['date-select.component.css'], + providers: [ { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DateSelectComponent), + multi: true + } ] }) -export class DateSelectComponent implements OnInit { +export class DateSelectComponent implements OnInit, ControlValueAccessor { @Input() initialIso: string; // ISO string @Input() initialYmd: string; // YYYY-MM-DD (uses local time zone) @@ -96,6 +102,7 @@ export class DateSelectComponent implements OnInit { const iso = date.toISOString(); this.onChangeAsDate.emit(date); this.onChangeAsYmd.emit(ymd); + this.propagateChange(ymd); this.onChangeAsIso.emit(iso); } @@ -115,6 +122,19 @@ export class DateSelectComponent implements OnInit { }; } + writeValue(value: string) { + if (value !== undefined) { + this.initialYmd = value; + } + } + + propagateChange = (_: any) => {}; + + registerOnChange(fn) { + this.propagateChange = fn; + } + + registerOnTouched() { } } diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html index 37e46d9c86..fd8a75508b 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html @@ -241,12 +241,47 @@ ngModel #bestOnes="ngModel"> The best libraries are: {{bestOnes.value | json}} +
+ + + + + + + + + + Result: {{templateEntry.value | json}} +
+ + + ngModel: {{dateString}} -
+

Or perhaps reactive forms interest you?

+
+ Choose your favorite law of library science: + + + + + + + + +
+ error + That isn't a real law of library science! +
+
+
+
+
+
+

Another reactive form!

void; notOneSelectedRow: (rows: IdlObject[]) => boolean; @@ -119,10 +123,25 @@ export class SandboxComponent implements OnInit { } ) }); + this.ranganathan = new FormGroup({ + 'law': new FormControl('second', (c: FormControl) => { + // An Angular custom validator + if ("wrong" === c.value.id) { + return { notALaw: 'That\'s not a real law of library science!' }; + } else { + return null; + } + } ) + }); + this.badOrgForm.get('badOrgSelector').valueChanges.subscribe(bad => { this.toast.danger('The fanciest libraries are: ' + JSON.stringify(bad.orgIds)); }); + this.ranganathan.get('law').valueChanges.subscribe(l => { + this.toast.success('You chose: ' + l.label); + }); + this.gridDataSource.data = [ {name: 'Jane', state: 'AZ'}, {name: 'Al', state: 'CA'}, diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.module.ts b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.module.ts index ec817d0d51..ebb886a67f 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.module.ts @@ -12,7 +12,7 @@ import {FormsModule, ReactiveFormsModule} from '@angular/forms'; StaffCommonModule, SandboxRoutingModule, FormsModule, - ReactiveFormsModule + ReactiveFormsModule, ], providers: [ ] -- 2.43.2