> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Get started with InstantSearch.js in Angular

> Integrate InstantSearch.js into an Angular app.

Use InstantSearch.js in your Angular projects to manage state and build custom search interfaces.

This approach lets you build a custom search solution without relying on Angular InstantSearch,
which isn't compatible with the latest Angular versions.
This simplifies development and gives you full control of your search interface.

<Card title="Explore source code" icon="github" href="https://github.com/algolia/doc-code-samples/tree/master/angular-instantsearch/using-instantsearch">
  Browse the source for the InstantSearch.js in Angular quickstart example on GitHub.
</Card>

## Base use-case

Rather than adding InstantSearch to a component directly,
store the instance in a service and expose utility methods.
You can reuse a single instance across multiple components and start it from just one component.

```js JavaScript icon=code theme={"system"}
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { liteClient as algoliasearch } from 'algoliasearch/lite';
import InstantSearch from 'instantsearch.js/es/lib/InstantSearch';
import type { IndexWidget, Widget } from 'instantsearch.js';

const searchClient = algoliasearch(
  'ALGOLIA_APPLICATION_ID',
  'ALGOLIA_SEARCH_API_KEY'
);

@Injectable({
  providedIn: 'root',
})
export class InstantSearchService {
  public instantSearchInstance: InstantSearch;

  constructor(router: Router) {
    this.instantSearchInstance = new InstantSearch({
      searchClient,
      indexName: 'instant_search',
      future: { preserveSharedStateOnUnmount: true },
    });
  }

  start() {
    this.instantSearchInstance.start();
  }

  addWidgets(widgets: Array<IndexWidget | Widget>) {
    this.instantSearchInstance.addWidgets(widgets);
  }

  removeWidgets(widgets: Array<IndexWidget | Widget>) {
    this.instantSearchInstance.removeWidgets(widgets);
  }
}
```

Inject this service into any component to access the InstantSearch instance:

```js Javascript icon=code theme={"system"}
import { Component } from "@angular/core";
import { InstantSearchService } from "../instant-search.service";

@Component({
  selector: "app-search",
  standalone: true,
  templateUrl: "./search.component.html",
})
export class SearchComponent {
  ngAfterContentInit() {
    this.InstantSearchService.start();
  }
}
```

Add widgets in any component using the service,
whether in the constructor or `ngOnInit`.
Start the instance in a single component with `ngAfterContentInit`.

Use connectors to track state changes and bind data to your components.

```js JavaScript icon=code theme={"system"}
import { Component } from '@angular/core';
import { InstantSearchService } from '../instant-search.service';
import { BaseHit } from 'instantsearch.js';
import { connectHits, connectSearchBox } from 'instantsearch.js/es/connectors';

@Component({
  selector: 'app-search',
  standalone: true,
  templateUrl: './search.component.html',
})
export class SearchComponent {
  public hits: BaseHit[] = [];
  public refine: (query: string) => void;
  public query: string;

  constructor(private InstantSearchService: InstantSearchService) {
    this.InstantSearchService.addWidgets([
      connectSearchBox(({ refine, query }) => {
        this.refine = refine;
        this.query = query;
      })({
        // ...widgetParameters
      }),
      connectHits(({ hits }) => {
        this.hits = hits;
      })({}),
    ]);
  }

  ngAfterContentInit() {
    this.InstantSearchService.start();
  }

  public search(event: Event) {
    this.refine!((event.target as HTMLInputElement).value);
  }
}
```

This lets you have multiple widgets in a single component.

The template automatically re-renders when the state updates with new results:

```html HTML icon=code-xml theme={"system"}
<input (input)="search($event)" [value]="query" />
<ul>
  @for (let hit of hits; track hit.objectID) {
    <li>{{ hit.name }}</li>
  }
</ul>
```

## Server-side rendering and routing

Because this service reads the Angular Router's initial state, routing integration works out of the box.

Server-side rendering also works without extra code, as Angular renders the page with the initial state coming from the network request.

```js JavaScript icon=code theme={"system"}
import { Injectable } from '@angular/core';
import { liteClient as algoliasearch } from 'algoliasearch/lite';
import history from 'instantsearch.js/es/lib/routers/history';
import InstantSearch from 'instantsearch.js/es/lib/InstantSearch';
import type { Widget } from 'instantsearch.js';
import { Router } from '@angular/router';

const searchClient = algoliasearch(
  'ALGOLIA_APPLICATION_ID',
  'ALGOLIA_SEARCH_API_KEY'
);

@Injectable({
  providedIn: 'root',
})
export class InstantSearchService {
  public instantSearchInstance: InstantSearch;

  constructor(router: Router) {
    this.instantSearchInstance = new InstantSearch({
      searchClient,
      indexName: 'instant_search',
      future: { preserveSharedStateOnUnmount: true },
      routing: {
        router: history({
          getLocation: () => {
            if (typeof window === 'undefined') {
              // No other way to get this in constructor
              return new URL(
                router['location']._locationStrategy._platformLocation.href
              ) as unknown as Location;
            }
            return window.location;
          },
        }),
      },
    });
  }
}
```

## Multi-index

The [`index`](/doc/api-reference/widgets/index-widget/js) widget supports multiple indices.

```js JavaScript icon=code theme={"system"}
import { Component } from '@angular/core';
import { InstantSearchService } from '../instant-search.service';
import { BaseHit } from 'instantsearch.js';
import { connectHits } from 'instantsearch.js/es/connectors';
import index from 'instantsearch.js/es/widgets/index/index';

@Component({
  selector: 'app-search',
  standalone: true,
  templateUrl: './search.component.html',
})
export class SearchComponent {
  public hits: BaseHit[] = [];

  constructor(private InstantSearchService: InstantSearchService) {
    this.InstantSearchService.addWidgets([
      index({ indexName: 'instant_search' }).addWidgets([
        connectHits(({ hits }) => {
          this.hits = hits;
        })({}),
      ]),
    ]);
  }

  ngAfterContentInit() {
    this.InstantSearchService.start();
  }
}
```
