Integrating Algolia InstantSearch with Angular

We’ve covered how to integrate Algolia InstantSearch in Vue.js apps, so let’s now go over how to do the same for an Angular app. This is now easy to do, thanks to the recently released Angular InstantSearch library.

Algolia offers a popular search as a service solution and makes creating and searching through indexed datasets easy. For example, the instant search on this very website is powered by Algolia and the Jekyll Algolia plugin.

Note that you'll need to use Angular InstantSearch with Angular 4+.

Setup

You’ll need an Algolia index that you can query. Creating and populating an index of data is an entirely different topic, so here we’ll assume that you have an index up already. For the purpose of this article, we’ll use a test index that Algolia makes available.

First, add the angular-instantsearch package to your Angular project:

# using Yarn:
$ yarn add angular-instantsearch

# or npm:
$ npm i angular-instantsearch

Next, in your app module or a feature module, import the NgAisModule and add it to your list of imports:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { NgAisModule } from 'angular-instantsearch';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    NgAisModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Omit the call to forRoot() if using NgAisModule in an Angular feature module.


Finally, you’ll also want to add the style files for InstantSearch. You can add the following entries to your .angular-cli.json’s styles array:

.angular-cli.json

...
"styles": [
  "styles.css",
  "../node_modules/angular-instantsearch/bundles/instantsearch.min.css",
  "../node_modules/angular-instantsearch/bundles/instantsearch-theme-algolia.min.css"
],
...

After making changes to the .angular-cli.json file you'll need to restart your local server.

Usage

Everything starts with the ng-ais-instantsearch component, which will be a wrapper for InstantSearch widgets. ng-ais-instantsearch takes a config object with the key and name of the Algolia index:

app.component.html

<ng-ais-instantsearch [config]="algoliaConfig">
  <!-- Widgets here -->
</ng-ais-instantsearch>

app.component.ts

import { Component } from '@angular/core';

@Component({ ... })
export class AppComponent {
  algoliaConfig = {
    apiKey: '3d9875e51fbd20c7754e65422f7ce5e1',
    appId: 'latency',
    indexName: 'bestbuy'
  };
}

And now that we have the wrapper in place and configured, we can start adding widgets to query and filter the index:

app.component.html

<ng-ais-instantsearch [config]="algoliaConfig">
  <ng-ais-search-box></ng-ais-search-box>
  <ng-ais-stats></ng-ais-stats>

  <h3>Filter by price range:</h3>
  <ng-ais-refinement-list attribute="salePrice_range"></ng-ais-refinement-list>
  <ng-ais-clear-refinements [autoHideContainer]="true" buttonLabel="Clear filter"></ng-ais-clear-refinements>

  <ng-ais-hits>
    <ng-template let-hits="hits" let-results="results">
      <!-- Nothing found? -->
      <div *ngIf="hits.length === 0">
        😢 Nothing found for
        <strong>{{results.query}}</strong>.
      </div>

      <div *ngFor="let hit of hits" class="result-card">
        <h2>
          <a [href]="hit.url" target="_blank">
            <ng-ais-highlight attribute="name" [hit]="hit">
            </ng-ais-highlight>
          </a>
        </h2>
        <p>{{ hit.shortDescription }}</p>

        <img [src]="hit.image" alt="{{ hit.name }} thumbnail">

        <p>
          <span class="price">{{ hit.salePrice | currency}}</span>
        </p>
      </div>
    </ng-template>
  </ng-ais-hits>

  <ng-ais-pagination></ng-ais-pagination>
</ng-ais-instantsearch>

Here we made use of a few widgets available with Algolia InstantSearch:

  • ng-ais-search-box: Search input to query the index.
  • ng-ais-stats: Stats about the search result.
  • ng-ais-refinement-list: Options to filter results by an attribute from the index (called a refinement).
  • ng-ais-clear-refinements: Button to clear the applied refinements.
  • ng-ais-hits: Where the magic happens and the results (hits) are displayed. Here we defined a template with ng-template so that we could format the hits with our own markup. We get access to the hits and results variables and each hit contains the data for one result as an object.
  • ng-ais-highlight: Widget that highlights the part of the search that matches the query.
  • ng-ais-pagination: Pagination widget for additional results.

And then let’s apply a bit of style to our search results:

app.component.css

ng-ais-clear-refinements {
  display: block;
  margin-top: 1rem;
}

::ng-deep .ais-Hits {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 10px;
  margin-top: 2rem;
}

::ng-deep .result-card {
  padding: 0.45rem 2rem;
  background: linear-gradient(45deg, #eee, white 50%);
  border-radius: 6px;
  border: 2px solid #f3f3f3;
}

@media (max-width: 900px) {
  ::ng-deep .ais-Hits {
    grid-template-columns: 1fr 1fr;
  }
}

Notice the use of the ::ng-deep selector to reach elements that are nested inside the widgets.

Here's our resulting UI:

Querying the sample Best Buy index

🕵️ Have fun querying your indices! You can refer to the official API docs for more details on the available widgets.

  Tweet It

🕵 Search Results

🔎 Searching...