Guides / Building Search UI / UI & UX patterns

Multi-Index Search with Angular InstantSearch

Multi-index search, or federated search, lets you search multiple data sources at once with the same query and gather results in a single search experience. This is a common pattern when building autocomplete search experiences, but also to offer centralized access to multiple sources of content developed and curated independently.

Multi-index search can also help you achieve complex UIs that display the content of the same index in several ways, for example to surface top-rated items before the list of results.

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.

Build a multi-source autocomplete experience

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.

Did you find this page helpful?