[ngbTypeahead]="filter"
[resultTemplate]="displayTemplate"
[inputFormatter]="formatDisplayString"
- (click)="click$.next($event.target.value)"
+ (click)="onClick($event)"
(blur)="onBlur()"
(selectItem)="selectorChanged($event)"
#instance="ngbTypeahead"/>
* <!-- see also <eg-combobox-entry> -->
* </eg-combobox>
*/
-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';
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<string>;
}
}
+ 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(''));
}
// 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
})
);
}
+
+ writeValue(value: any) {
+ if (value !== undefined) {
+ this.startId = value;
+ this.startIdFiresOnChange = true;
+ }
+ }
+
+ propagateChange = (_: any) => {};
+
+ registerOnChange(fn) {
+ this.propagateChange = fn;
+ }
+
+ registerOnTouched() { }
+
}
-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:
@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)
const iso = date.toISOString();
this.onChangeAsDate.emit(date);
this.onChangeAsYmd.emit(ymd);
+ this.propagateChange(ymd);
this.onChangeAsIso.emit(iso);
}
};
}
+ writeValue(value: string) {
+ if (value !== undefined) {
+ this.initialYmd = value;
+ }
+ }
+
+ propagateChange = (_: any) => {};
+
+ registerOnChange(fn) {
+ this.propagateChange = fn;
+ }
+
+ registerOnTouched() { }
}
ngModel #bestOnes="ngModel">
</eg-org-family-select>
The best libraries are: {{bestOnes.value | json}}
+ <hr>
+ <eg-combobox ngModel #templateEntry="ngModel">
+ <eg-combobox-entry entryId="Bacteria"></eg-combobox-entry>
+ <eg-combobox-entry entryId="Archaea"></eg-combobox-entry>
+ <eg-combobox-entry entryId="Protozoa"></eg-combobox-entry>
+ <eg-combobox-entry entryId="Chromista"></eg-combobox-entry>
+ <eg-combobox-entry entryId="Plantae"></eg-combobox-entry>
+ <eg-combobox-entry entryId="Fungi"></eg-combobox-entry>
+ <eg-combobox-entry entryId="Animalia"></eg-combobox-entry>
+ </eg-combobox>
+ Result: {{templateEntry.value | json}}
+ <hr>
+ <eg-date-select [(ngModel)]="dateString">
+ </eg-date-select>
+ ngModel: {{dateString}}
</div>
</div>
</div>
- <form class="card col-md-6" [formGroup]="badOrgForm">
+ <form class="card col-md-4" [formGroup]="ranganathan">
<div class="card-body">
<h3 class="card-title">Or perhaps reactive forms interest you?</h3>
<div class="card-text">
+ Choose your favorite law of library science:
+ <eg-combobox formControlName="law" value="second">
+ <eg-combobox-entry entryId="first" entryLabel="Books are for use" i18n-entryLabel></eg-combobox-entry>
+ <eg-combobox-entry entryId="second" entryLabel="Every person his or her book" i18n-entryLabel></eg-combobox-entry>
+ <eg-combobox-entry entryId="third" entryLabel="Every book its reader" i18n-entryLabel></eg-combobox-entry>
+ <eg-combobox-entry entryId="fourth" entryLabel="Save the time of the reader" i18n-entryLabel></eg-combobox-entry>
+ <eg-combobox-entry entryId="fifth" entryLabel="Library is a growing organism" i18n-entryLabel></eg-combobox-entry>
+ <eg-combobox-entry entryId="wrong" entryLabel="42" i18n-entryLabel></eg-combobox-entry>
+ </eg-combobox>
+ <div *ngIf="!ranganathan.valid" class="alert alert-danger">
+ <span class="material-icons">error</span>
+ <span i18n>That isn't a real law of library science!</span>
+ </div>
+ </div>
+ </div>
+ </form>
+ <form class="card col-md-4" [formGroup]="badOrgForm">
+ <div class="card-body">
+ <h3 class="card-title">Another reactive form!</h3>
+ <div class="card-text">
<eg-org-family-select
formControlName="badOrgSelector"
labelText="Choose the fanciest libraries">
badOrgForm: FormGroup;
+ ranganathan: FormGroup;
+
+ dateString = '2019-09-09';
+
complimentEvergreen: (rows: IdlObject[]) => void;
notOneSelectedRow: (rows: IdlObject[]) => boolean;
} )
});
+ 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'},
StaffCommonModule,
SandboxRoutingModule,
FormsModule,
- ReactiveFormsModule
+ ReactiveFormsModule,
],
providers: [
]