Multi-Index Search with Angular InstantSearch
If you want to search multiple indices, there are a couple of approaches you can take:
- Synchronize two InstantSearch indices and share a single search box to display multiple hits from different indices.
- Use Autocomplete to target multiple indices.
The source code for both examples is on GitHub.
Synchronize two InstantSearch indices
This example uses a single input to search multiple indices. It uses the ais-index
to query two indices at the same time: players
and actors
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// app.component.ts
import { Component } from '@angular/core';
import algoliasearch from 'algoliasearch/lite';
const searchClient = algoliasearch(
'latency',
'6be0576ff61c053d5f9a3225e2a90f76'
);
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
config = {
indexName: 'instant_search',
searchClient,
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- app.component.html -->
<ais-instantsearch [config]="config">
<ais-search-box placeholder=""></ais-search-box>
<ais-index indexName="actors">
<h2>Actors</h2>
<ais-hits></ais-hits>
</ais-index>
<ais-index indexName="players">
<h2>Players</h2>
<ais-hits></ais-hits>
</ais-index>
</ais-instantsearch>
The example uses a custom search box and injects the query into two InstantSearch instances with the ais-configure
component.
You can find the complete example on GitHub.
Use Autocomplete
This example builds an Autocomplete to search multiple indices. It’s built with Angular Material’s Autocomplete and the connectAutocomplete
component. The only difference to the previous guide is how hits are appended to Autocomplete.
The ais-autocomplete
component takes indices
as a prop. This is an array of additional indices to do the search in, in this case the actors
index.
First make sure you have the correct setup to use Angular Material’s components, then import MatInputModule and MatAutocompleteModule inside your project.
$
ng add @angular/material
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { NgAisModule } from 'angular-instantsearch';
import { MatInputModule, MatAutocompleteModule } from '@angular/material';
@NgModule({
declarations: [
AppComponent
],
imports: [
NgAisModule.forRoot(),
BrowserModule,
BrowserAnimationsModule,
MatInputModule,
MatAutocompleteModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Now create a new component autocomplete.component.ts
inheriting from BaseWidget
and connect it to your instant-search instance to connectAutocomplete
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// autocomplete.component.ts
import {
Component,
Inject,
forwardRef,
Output,
EventEmitter, Optional
} from "@angular/core";
import {NgAisIndex, NgAisInstantSearch, TypedBaseWidget} from "angular-instantsearch";
import {connectAutocomplete} from "instantsearch.js/es/connectors";
import {
AutocompleteWidgetDescription,
AutocompleteConnectorParams
} from "instantsearch.js/es/connectors/autocomplete/connectAutocomplete";
@Component({
selector: 'app-autocomplete',
template: ` ... `,
})
export class AutocompleteComponent extends TypedBaseWidget<
AutocompleteWidgetDescription,
AutocompleteConnectorParams
> {
state: AutocompleteWidgetDescription['renderState'] = {
currentRefinement: '',
refine: () => null,
indices: [],
};
@Output() onQuerySuggestionClick = new EventEmitter<{ query: string }>();
constructor(
@Inject(forwardRef(() => NgAisIndex))
@Optional()
public parentIndex: NgAisIndex,
@Inject(forwardRef(() => NgAisInstantSearch))
public instantSearchInstance: NgAisInstantSearch
) {
super('Autocomplete');
this!.createWidget(connectAutocomplete, {});
}
public handleChange($event: KeyboardEvent) {
this.state.refine(($event.target as HTMLInputElement).value);
}
public ngOnInit() {
super.ngOnInit();
}
}
Now you just need to use Angular Material Autocomplete component and feed it with the data from the indices.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// autocomplete.component.ts
@Component({
selector: 'app-autocomplete',
template: `
<div>
<input
matInput
[matAutocomplete]="auto"
(keyup)="handleChange($event)"
style="width: 100%; padding: 10px"
/>
<mat-autocomplete #auto="matAutocomplete" style="height: 800px">
<div *ngFor="let index of state.indices.slice(1) || []">
<mat-optgroup>{{ index.indexName }}</mat-optgroup>
<mat-option
*ngFor="let option of index.hits"
[value]="option.name"
(click)="onQuerySuggestionClick.emit({ query: option.name })"
>
<ais-highlight [hit]="option" attribute="name"></ais-highlight>
</mat-option>
</div>
</mat-autocomplete>
</div>
`
})
export class Autocomplete extends TypedBaseWidget<...> { /* ... */ }
Now use the newly created Autocomplete component in your code.
1
2
3
4
5
6
<ais-instantsearch [config]="config">
<ais-configure [searchParameters]="{ hitsPerPage: 3 }"></ais-configure>
<ais-index indexName="players"></ais-index>
<ais-index indexName="actors"></ais-index>
<app-autocomplete></app-autocomplete>
</ais-instantsearch>
The Autocomplete component is now searching in two indices: players
and actors
.
The focus of this guide is on searching multiple indices. The Autocomplete implementation isn’t covered in depth because it has a dedicated guide.