I am using the NgbTypeahead component from NG-Boostrap 6.0.3 in my Angular 9 app. The first one works fine, but my form has quite a few.
Do I need to add a separate ViewChild and a separate search function for each one of them? Or am I missing something? Can someone point me to an example with more than one?
For reference, here's a Stackblitz with just the one.
well, really my comment is NOT correct, imagine you has 2 ngbTypeHead You need that focus$ and click$ was an array, for this, you can use map, some like
focus$ = [0,1].map(_=>new Subject<string>());
click$ = [0,1].map(_=>new Subject<string>());
Well, you can also too make some like (I use a fool array and map) but it is the same than:
focus$ = [new Subject<string>(),new Subject<string>()];
I use an array to the model
model: any[]=[];
And change the searchFunction that received as parameters: an index, a instance and a term (the index is necesary to make reference to the subjects
searchType(index,instance, text$) {
return (text$: Observable<string>) => {
const debouncedText$ = text$.pipe(
debounceTime(200),
distinctUntilChanged()
);
const clicksWithClosedPopup$ = this.click$[index].pipe(
filter(() => !instance.isPopupOpen())
);
const inputFocus$ = this.focus$[index];
return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
map(term =>
(term === ""
? states
: states.filter(
v => v.toLowerCase().indexOf(term.toLowerCase()) > -1
)
).slice(0, 10)
)
);
};
}
Then, the only we need is change our ngbTypeahead
<input
...
[(ngModel)]="model[index]"
[ngbTypeahead]="searchType(i,instance,$text)"
(focus)="focus$[i].next($any($event).target.value)"
(click)="click$[i].next($any($event).target.value)"
#instance="ngbTypeahead"
>
You can see an example in stackblitz
Update if we need differents data, we can improve the function search passing the "data", so, if we add a new parameter to search:
searchType(index,instance, data,text$) { //<--pass "data"
return (text$: Observable<string>) => {
const debouncedText$ = text$.pipe(
debounceTime(200),
distinctUntilChanged()
);
const clicksWithClosedPopup$ = this.click$[index].pipe(
filter(() => !instance.isPopupOpen())
);
const inputFocus$ = this.focus$[index];
return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
map(term =>
(term === ""
? data //<--here use data
: data.filter( //<--here use data too
v => v.toLowerCase().indexOf(term.toLowerCase()) > -1
)
).slice(0, 10)
)
);
};
}
We can change the call and write:
[ngbTypeahead]="searchType(i,instance,states,$text)"
Another option is, according to the "index" search in one or another array, so the function becomes like
searchType(index,instance, text$) {
const data=index==0?states:this.fruits; //<--the data according the index
return (text$: Observable<string>) => {
const debouncedText$ = text$.pipe(
debounceTime(200),
distinctUntilChanged()
);
const clicksWithClosedPopup$ = this.click$[index].pipe(
filter(() => !instance.isPopupOpen())
);
const inputFocus$ = this.focus$[index];
return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
map(term =>
(term === ""
? data //<--here use data
: data.filter( //<--here use data too
v => v.toLowerCase().indexOf(term.toLowerCase()) > -1
)
).slice(0, 10)
)
);
};
}