ngx-bootstrap
ngx-bootstrap copied to clipboard
feat(typeahead): support multiple search field values
I am trying to use typeahead in a scenario where we need to filter the search result based on multiple fields. Lets say we have an object like this
[{
id: 1
name: "Stockholm",
country: "Sweden"
}, {
id: 1
name: "Gothenburg",
country: "Sweden"
}]
Then if I search on "Stock" I want the Stockholm object as result. If I search for "Swe" I want both Stockholm and Gothenburg. The matching function should therefore look for a match on both the name and country property.
multi select is planned feature
@valorkin This doesn't feel like a concern of typeahead. Instead @Abrissirba you should write a service that does this. This is based on the asynchronous example in the documentation.
public getCitiesAsObservable(token:string):Observable<any> {
return Observable.of(
this.citiesComplex.filter((city:any) => {
return city.name.startsWith(token) || city.country.startsWith(token);
})
);
}
I use this technique searching for people when matching on first and last name.
@critchie elegant solution! Thank you :)
This is very much needed, I don't think the OP wants there to be multi select, just be able to filter the drop down list by more than one field in an array of objects. He or she can then select just one from that list.
Once you have moved beyond the simple string/array of strings comparison the typeahead really can't make any assumptions about the filtering algorithm. To do what is being requested @valorkin and company would have to make assumptions about the filtering algorithm. The first assumption that comes to mind is what relational operator to use when determining a match. Is it "name AND country" or is it "name OR country"?
Returning an Observable where you explicitly define the filtering is much cleaner IMO.
Or allow predicates, or configurable pipes BTW 2ND will be available in next Typeahead version ;)
how is the progress on this?
@sanyooh nearest 2 weeks I am focused on new datepicker (available from v1.9.0) http://valor-software.com/ngx-bootstrap/#/datepicker#examples then merge to ng v4+ (and 5) only (1-2 days) then I will focus on typeahead
Looking forward to this, it would be great to be able to do something like in uib-typeahead, ie: typeaheadOptionField(id+', '+title)
I have a similar problem. I have an array of objects. I would like the typeahead to allow me to specify a field to use to match, and a field to use for display, and another field to use for the value.
- A match should return an object from my collection.
- The input field should show the value of the 'display' property.
- The value should be set to the value of the named 'value' property.
- I should still be able to use a template to display any combination of properties from my objects. (This currently works fine)
Do you think that would be possible?
I am getting ERROR TypeError: Cannot read property 'startsWith' of undefined. Can you please help me?
Search by multiple fields, Any updates on this implementation ?
I'm with @jschank in that Typeahead should be more flexible in what is matched, displayed, and used for the selected value(s).
Any updates on this?
I'm not sure if I need to open a new issue, but I was wondering if TypeAheadOptionField supports multiple strings. I'd like to display a second property in my current dropdown on the Options field:
The html for the dropdown:
<div class="row">
<div class="col-lg-12">
<input name="typeahead" [(ngModel)]="asyncSelected"
[typeaheadAsync]="true" [typeahead]="dataSource"
(typeaheadLoading)="changeTypeaheadLoading($event)"
(typeaheadOnSelect)="typeaheadOnSelect($event)"
[typeaheadOptionsLimit]="7"
typeaheadOptionField="schoolName"
placeholder="Start typing School Name..."
typeaheadWaitMs="1000" class="form-control">
<div *ngIf="typeaheadLoading">Loading</div>
</div>
</div>
and the way I'm binding to it from my TS component:
this.dataSource = Observable.create((observer: any) => {
observer.next(this.asyncSelected);
})
.pipe(
mergeMap((token: string) => {
return this.schoolService.searchSchool(token, 1).pipe(map(data => data.schools));
})
);
}
asyncSelected: string;
typeaheadLoading: boolean;
typeaheadNoResults: boolean;
dataSource: Observable<any>;
changeTypeaheadLoading(e: boolean): void {
this.typeaheadLoading = e;
}
typeaheadOnSelect(e: TypeaheadMatch): void {
this.asyncSelected = null;
this.addSchool(e.item);
}
My school component also has a string address property that needs to also display in the search results. Not exactly sure how I'd do it.
Also the documentation link provided above: https://valor-software.com/ng2-bootstrap/#/typeahead is broken can someone update the link?
any updates on this? :100:
I solved it doing this
ngOnInit(): void {
// we want the typeahead to search on email and
// firstName + lastName... so we create a searchQuery property
// and duplicate records
this.storeService.users$
.pipe(
filter(res => res !== null),
takeUntil(this.destroy$)
)
.subscribe(res => {
// get the users by email address
// and create a searchQuery property
const usersByEmail = _.cloneDeep(res);
usersByEmail.forEach(x => {
x.searchQuery = `${x.email}`.toLocaleLowerCase().replace(/ /gi, '');
});
// get the users with firstName and lastName
const usersWithFullName = _.cloneDeep(res).filter(x => x.firstName);
usersWithFullName.forEach(x => {
x.searchQuery = `${x.firstName}${x.lastName}`.toLocaleLowerCase().replace(/ /gi, '');
});
this.users = [...usersWithFullName, ...usersByEmail];
});
}
The solution for @awaheed1 is to use a templated list.
<input [(ngModel)]="asyncSelected"
[typeahead]="dataSource"
[typeaheadAsync]="true"
[typeaheadScrollable]="true"
[typeaheadItemTemplate]="rct"
[typeaheadOptionField]="iFormat"
[typeaheadOptionsInScrollableView]="10"
(typeaheadOnSelect)="onSelect($event)"
placeholder="Locations loaded via observable"
class="form-control">
<!-- template for resource typeahead -->
<ng-template #rct let-rc="item">
<div class="mb-0">
<h5 class="m-1">{{rc.resourceRef}} - {{rc.newResourceType}}</h5>
</div>
</ng-template>
This allows you to display multiple options with your own make-up/lay-out.
The problem I am facing thereafter is that the typeaheadOptionField
can only display a single field from the object, it does not appear to be able to show me the exact selected result?
Now I understand I can map the two properties to a single string and have that be the search and selection criteria with the original object as a seperate property, but that doesn't seem to be an elegant solution?
ngb-typeahead allows you to use a function as the displayed value, but that doesn't seem to work on ngx-typeahead?
@critchie 's answer is still valid. The update link is below: https://valor-software.com/ngx-bootstrap/old/3.0.1/#/typeahead#async-data
An typeaheadOptionFieldFn
should be enough, so we can pass a callback receiving the items and returning the final string to search the hint with. Like this:
<input id="username" type="text" class="form-control"
[ngModel]="data"
[typeahead]="users" autocomplete="off"
[typeaheadOptionFieldFn]="optionFieldFn"
[typeaheadScrollable]="true">
optionFieldFn(match: TypeaheadMatch) {
const {item} = match;
return `${item.name}${item.surname}${item.id}`;
}
typeaheadOptionField
already takes function but its useless in this case as it doesn't provide any parameters