Add bootstrap typeahead control to NgxForm
Install
Install package
Import module
import{NgxFormTypeaheadModule}from'@ngxform/ng-bootstrap-typeahead'; ... @NgModule({ ... imports: [FormsModule,ReactiveFormsModule,NgxFormModule,NgxFormTypeaheadModule],})
Input Option
interfaceNgxBootstrapTypeaheadOptionextendsNgxFormControlOption{defaultValue?: any;hostClass?: any;ngClass?: any;options?: any[];ngbTypeahead?: (text: Observable<string>)=>Observable<readonlyany[]>;resultTemplate?: TemplateRef<ResultTemplateContext>;windowTemplate?: TemplateRef<WindowTemplateContext>;inputFormatter?: (item: any)=>string;openOnFocus?: boolean;focus?: boolean | Subject<boolean>;disabled?: boolean;fullWithWindow?: boolean;}
Usage
Simple typeahead
simple-typeahead.component.html
<form[formGroup]="demoForm" (ngSubmit)="onSubmit()"><ng-templatengxFormAnchor[controls]="demoForm.controls"></ng-template><buttontype="submit" class="btn btn-primary">Submit</button></form>
simple-typeahead.component.ts
import{NgxBootstrapTypeaheadControl}from'@ngxform/ng-bootstrap-typeahead';import{Component,OnInit}from'@angular/core';import{NgxFormGroup}from'@ngxform/platform';import{Validators}from'@angular/forms'; @Component({selector: 'app-basic',templateUrl: './basic.component.html',styleUrls: ['./basic.component.scss']})exportclassSimpleTypeaheadComponentimplementsOnInit{publicdemoForm: NgxFormGroup;ngOnInit(): void{consttypeaheadOptions: {name: string; flag: string}[]=[{name: 'Alabama',flag: '5/5c/Flag_of_Alabama.svg/45px-Flag_of_Alabama.svg.png'},{name: 'Alaska',flag: 'e/e6/Flag_of_Alaska.svg/43px-Flag_of_Alaska.svg.png'},{name: 'Arizona',flag: '9/9d/Flag_of_Arizona.svg/45px-Flag_of_Arizona.svg.png'},{name: 'Arkansas',flag: '9/9d/Flag_of_Arkansas.svg/45px-Flag_of_Arkansas.svg.png'},{name: 'California',flag: '0/01/Flag_of_California.svg/45px-Flag_of_California.svg.png'},{name: 'Colorado',flag: '4/46/Flag_of_Colorado.svg/45px-Flag_of_Colorado.svg.png'},{name: 'Connecticut',flag: '9/96/Flag_of_Connecticut.svg/39px-Flag_of_Connecticut.svg.png'},{name: 'Delaware',flag: 'c/c6/Flag_of_Delaware.svg/45px-Flag_of_Delaware.svg.png'},{name: 'Florida',flag: 'f/f7/Flag_of_Florida.svg/45px-Flag_of_Florida.svg.png'}];this.demoForm=newNgxFormGroup({typeahead: newNgxBootstrapTypeaheadControl('',[Validators.required,Validators.email,Validators.minLength(3)],[],{label: 'NgBootstrap Typeahead',controlClass: ['form-control'],ngClass: 'd-flex flex-column form-group',options: typeaheadOptions,inputFormatter: (item: any)=>item.name,openOnFocus: true,errorMessages: [{key: 'required',message: 'This field is required'},]})});}onSubmit(): void{ this.demoForm.submitted=true;console.log(this.demoForm.value);}}
Custom template
Custom Result Template
custom-result-template.component.html
<ng-template#resultTemplatelet-r="result" let-t="term"><img[src]="'https://upload.wikimedia.org/wikipedia/commons/thumb/' + r['flag']" class="mr-1" style="width: 16px"> {{r.name}} </ng-template><form[formGroup]="demoForm" (ngSubmit)="onSubmit()"><ng-templatengxFormAnchor[controls]="demoForm.controls"></ng-template><buttontype="submit" class="btn btn-primary">Submit</button></form>
custom-result-template.component.ts
import{NgxBootstrapTypeaheadControl,ResultTemplateContext}from'@ngxform/ng-bootstrap-typeahead';import{Component,OnInit,TemplateRef,ViewChild}from'@angular/core';import{NgxFormGroup}from'@ngxform/platform';import{Validators}from'@angular/forms'; @Component({selector: 'app-basic',templateUrl: './basic.component.html',styleUrls: ['./basic.component.scss']})exportclassCustomResultTemplateComponentimplementsOnInit{publicdemoForm: NgxFormGroup; @ViewChild('resultTemplate',{static: true})resultTemplate: TemplateRef<ResultTemplateContext>;ngOnInit(): void{consttypeaheadOptions: {name: string; flag: string}[]=[{name: 'Alabama',flag: '5/5c/Flag_of_Alabama.svg/45px-Flag_of_Alabama.svg.png'},{name: 'Alaska',flag: 'e/e6/Flag_of_Alaska.svg/43px-Flag_of_Alaska.svg.png'},{name: 'Arizona',flag: '9/9d/Flag_of_Arizona.svg/45px-Flag_of_Arizona.svg.png'},{name: 'Arkansas',flag: '9/9d/Flag_of_Arkansas.svg/45px-Flag_of_Arkansas.svg.png'},{name: 'California',flag: '0/01/Flag_of_California.svg/45px-Flag_of_California.svg.png'},{name: 'Colorado',flag: '4/46/Flag_of_Colorado.svg/45px-Flag_of_Colorado.svg.png'},{name: 'Connecticut',flag: '9/96/Flag_of_Connecticut.svg/39px-Flag_of_Connecticut.svg.png'},{name: 'Delaware',flag: 'c/c6/Flag_of_Delaware.svg/45px-Flag_of_Delaware.svg.png'},{name: 'Florida',flag: 'f/f7/Flag_of_Florida.svg/45px-Flag_of_Florida.svg.png'}];this.demoForm=newNgxFormGroup({typeahead: newNgxBootstrapTypeaheadControl('',[Validators.required,Validators.email,Validators.minLength(3)],[],{label: 'NgBootstrap Typeahead',controlClass: ['form-control'],ngClass: 'd-flex flex-column form-group',options: typeaheadOptions,resultTemplate: this.resultTemplate,inputFormatter: (item: any)=>item.name,openOnFocus: true,errorMessages: [{key: 'required',message: 'This field is required'},]})});}onSubmit(): void{ this.demoForm.submitted=true;console.log(this.demoForm.value);}}
Custom Window Template
custom-window-template.component.html
<ng-template#windowTemplatelet-results="results" let-term="term" let-formatter="formatter" let-markActive="markActive" let-select="select" let-activeIdx="activeIdx"><ng-template#rtlet-r="result" let-t="term"><img[src]="'https://upload.wikimedia.org/wikipedia/commons/thumb/' + r['flag']" class="mr-1" style="width: 16px" /> {{ r.name }} </ng-template><ng-templatengFor[ngForOf]="results" let-resultlet-idx="index"><buttontype="button" class="dropdown-item" role="option" [id]="id + '-' + idx" [class.active]="idx === activeIdx" (mouseenter)="markActive(idx)" (click)="select(result)"><ng-template[ngTemplateOutlet]="resultTemplate || rt" [ngTemplateOutletContext]="{ result: result, term: term, formatter: formatter }"></ng-template></button></ng-template></ng-template><form[formGroup]="demoForm" (ngSubmit)="onSubmit()"><ng-templatengxFormAnchor[controls]="demoForm.controls"></ng-template><buttontype="submit" class="btn btn-primary">Submit</button></form>
custom-window-template.component.ts
import{NgxBootstrapTypeaheadControl,WindowTemplateContext}from'@ngxform/ng-bootstrap-typeahead';import{Component,OnInit,TemplateRef,ViewChild}from'@angular/core';import{NgxFormGroup}from'@ngxform/platform';import{Validators}from'@angular/forms'; @Component({selector: 'app-basic',templateUrl: './basic.component.html',styleUrls: ['./basic.component.scss']})exportclassCustomWindowTemplateComponentimplementsOnInit{publicdemoForm: NgxFormGroup; @ViewChild('windowTemplate',{static: true})windowTemplate: TemplateRef<WindowTemplateContext>;ngOnInit(): void{consttypeaheadOptions: {name: string; flag: string}[]=[{name: 'Alabama',flag: '5/5c/Flag_of_Alabama.svg/45px-Flag_of_Alabama.svg.png'},{name: 'Alaska',flag: 'e/e6/Flag_of_Alaska.svg/43px-Flag_of_Alaska.svg.png'},{name: 'Arizona',flag: '9/9d/Flag_of_Arizona.svg/45px-Flag_of_Arizona.svg.png'},{name: 'Arkansas',flag: '9/9d/Flag_of_Arkansas.svg/45px-Flag_of_Arkansas.svg.png'},{name: 'California',flag: '0/01/Flag_of_California.svg/45px-Flag_of_California.svg.png'},{name: 'Colorado',flag: '4/46/Flag_of_Colorado.svg/45px-Flag_of_Colorado.svg.png'},{name: 'Connecticut',flag: '9/96/Flag_of_Connecticut.svg/39px-Flag_of_Connecticut.svg.png'},{name: 'Delaware',flag: 'c/c6/Flag_of_Delaware.svg/45px-Flag_of_Delaware.svg.png'},{name: 'Florida',flag: 'f/f7/Flag_of_Florida.svg/45px-Flag_of_Florida.svg.png'}];this.demoForm=newNgxFormGroup({typeahead: newNgxBootstrapTypeaheadControl('',[Validators.required,Validators.email,Validators.minLength(3)],[],{label: 'NgBootstrap Typeahead',controlClass: ['form-control'],ngClass: 'd-flex flex-column form-group',options: typeaheadOptions,inputFormatter: (item: any)=>item.name,openOnFocus: true,errorMessages: [{key: 'required',message: 'This field is required'},{key: 'email',message: 'Email is invalid'},{key: 'minlength',message: 'Min length is 3'}]})});}onSubmit(): void{ this.demoForm.submitted=true;console.log(this.demoForm.value);}}
Dynamic data
dynamic.component.html
<form[formGroup]="demoForm" (ngSubmit)="onSubmit()"><ng-templatengxFormAnchor[controls]="demoForm.controls"></ng-template><buttontype="submit" class="btn btn-primary">Submit</button></form>
dynamic.component.ts
import{Component,OnInit,TemplateRef,ViewChild}from'@angular/core';import{NgxFormGroup}from'@ngxform/platform';import{Validators}from'@angular/forms';import{catchError,debounceTime,distinctUntilChanged,map,switchMap}from'rxjs/operators';import{Observable}from'rxjs';import{HttpClient}from'@angular/common/http';import{NgxBootstrapTypeaheadControl,WindowTemplateContext}from'@ngxform/ng-bootstrap-typeahead'; @Component({selector: 'app-dynamic',templateUrl: './dynamic.component.html',styleUrls: ['./dynamic.component.scss']})exportclassDynamicComponentimplementsOnInit{publicdemoForm: NgxFormGroup; @ViewChild('windowTemplate',{static: true})windowTemplate: TemplateRef<WindowTemplateContext>;constructor(privatehttp: HttpClient){}ngOnInit(): void{constsearch=(text$: Observable<string>)=>text$.pipe(debounceTime(200),distinctUntilChanged(),switchMap((term)=>{if(term !== undefined&&term !== ''){returnthis.http.get(`https://restcountries.eu/rest/v2/name/${term.toLowerCase()}`).pipe(catchError((error)=>error));}else{returnthis.http.get('https://restcountries.eu/rest/v2/all').pipe(catchError((error)=>error));}}),map((data: any[])=>{returndata.map((item)=>Object.assign(item,{key: item.name}));}));this.demoForm=newNgxFormGroup({typeahead: newNgxBootstrapTypeaheadControl('',[Validators.required,Validators.email,Validators.minLength(3)],[],{label: 'NgBootstrap Typeahead',controlClass: ['form-control'],ngClass: 'd-flex flex-column form-group',inputFormatter: (item: any)=>item.name,ngbTypeahead: search,errorMessages: [{key: 'required',message: 'This field is required'},{key: 'email',message: 'Email is invalid'},{key: 'minlength',message: 'Min length is 3'}]})});}onSubmit(): void{this.demoForm.submitted=true;console.log(this.demoForm.value);}}