UI libraries / Angular InstantSearch / Widgets

Angular InstantSearch isn’t compatible with Angular’s Ivy view engine. We’re investigating how best to support this. For more information and to vote for Algolia’s support of Angular 16 and beyond, see the GitHub issue Algolia Support for Angular InstantSearch

Signature
<ais-pagination
  // Optional parameters
  [padding]="number"
  [totalPages]="number"
  [showFirst]="boolean"
  [showLast]="boolean"
  [showPrevious]="boolean"
  [showNext]="boolean"
></ais-pagination>
Import
1
2
3
4
5
6
7
8
import { NgAisPaginationModule } from 'angular-instantsearch';

@NgModule({
  imports: [
    NgAisPaginationModule,
  ],
})
export class AppModule {}

1. Follow additional steps in Optimize build size to ensure your code is correctly bundled.
2. This imports all the widgets, even the ones you don’t use. Read the Getting started guide for more information.

About this widget

The ais-pagination widget displays a pagination system which lets users change the current page of search results.

The Algolia search engine limits paginating to 1,000 hits per page.

Examples

1
<ais-pagination></ais-pagination>

Props

Parameter Description
padding
type: number
default: 3
Optional

How many page links to display around the current page.

1
<ais-pagination padding="2"></ais-pagination>
totalPages
type: number
default: Infinity
Optional

The maximum number of pages to display (and to allow navigating to).

1
<ais-pagination totalPages="5"></ais-pagination>
showFirst
type: boolean
default: true
Optional

Display the first page link.

1
<ais-pagination showFirst="false"></ais-pagination>
showLast
type: boolean
default: true
Optional

Display the last page link.

1
<ais-pagination showLast="false"></ais-pagination>
showPrevious
type: boolean
default: true
Optional

Display the previous page link.

1
<ais-pagination showPrevious="false"></ais-pagination>
showNext
type: boolean
default: true
Optional

Display the next page link.

1
<ais-pagination showNext="false"></ais-pagination>

HTML output

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
<div class="ais-Pagination">
  <ul class="ais-Pagination-list">
    <li class="ais-Pagination-item ais-Pagination-item--firstPage ais-Pagination-item--disabled">
      <span class="ais-Pagination-link" aria-label="First">‹‹</span>
    </li>
    <li class="ais-Pagination-item ais-Pagination-item--previousPage ais-Pagination-item--disabled">
      <span class="ais-Pagination-link" aria-label="Previous"></span>
    </li>
    <li class="ais-Pagination-item ais-Pagination-item--selected">
      <a class="ais-Pagination-link" href="#">1</a>
    </li>
    <li class="ais-Pagination-item ais-Pagination-item--page">
      <a class="ais-Pagination-link" href="#">2</a>
    </li>
    <li class="ais-Pagination-item ais-Pagination-item--page">
      <a class="ais-Pagination-link" href="#">3</a>
    </li>
    <li class="ais-Pagination-item">
      <a class="ais-Pagination-link" href="#">4</a>
    </li>
    <li class="ais-Pagination-item ais-Pagination-item--nextPage">
      <a class="ais-Pagination-link" aria-label="Next" href="#"></a>
    </li>
    <li class="ais-Pagination-item ais-Pagination-item--lastPage">
      <a class="ais-Pagination-link" aria-label="Last" href="#">››</a>
    </li>
  </ul>
</div>

Customize the UI with connectPagination

If you want to create your own UI of the ais-pagination widget, you can combine the connectPagination connector with the TypedBaseWidget class.

1. Extend the TypedBaseWidget class

First of all, you will need to write some boilerplate code to initialize correctly the TypedBaseWidget class. This happens in the constructor() of your class extending the TypedBaseWidget class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Component, Inject, forwardRef, Optional } from '@angular/core';
import { TypedBaseWidget, NgAisInstantSearch, NgAisIndex } from 'angular-instantsearch';

@Component({
  selector: 'app-pagination',
  template: '<p>It works!</p>'
})
export class Pagination extends TypedBaseWidget {
  constructor(
    @Inject(forwardRef(() => NgAisIndex))
    @Optional()
    public parentIndex: NgAisIndex,
    @Inject(forwardRef(() => NgAisInstantSearch))
    public instantSearchInstance: NgAisInstantSearch
  ) {
    super('Pagination');
  }
}

There are a couple of things happening in this boilerplate:

  • create a Pagination class extending TypedBaseWidget
  • reference the <ais-instantsearch> parent component instance on the Pagination widget class
  • set app-pagination as a selector, so we can use our component as <app-pagination></app-pagination>

2. Connect your custom widget

The TypedBaseWidget class has a method called createWidget() which takes two arguments: the connector to use and an object of options (instance options) for this connector. We call this method at ngOnInit. This component now implements OnInit.

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
import { Component, Inject, forwardRef, Optional } from '@angular/core';
import { TypedBaseWidget, NgAisInstantSearch, NgAisIndex } from 'angular-instantsearch';

import connectPagination, {
  PaginationWidgetDescription,
  PaginationConnectorParams
} from 'instantsearch.js/es/connectors/pagination/connectPagination';

@Component({
  selector: 'app-pagination',
  template: '<p>It works!</p>'
})
export class Pagination extends TypedBaseWidget<PaginationWidgetDescription, PaginationConnectorParams> {
  public state: PaginationWidgetDescription['renderState']; // Rendering options
  constructor(
    @Inject(forwardRef(() => NgAisIndex))
    @Optional()
    public parentIndex: NgAisIndex,
    @Inject(forwardRef(() => NgAisInstantSearch))
    public instantSearchInstance: NgAisInstantSearch
  ) {
    super('Pagination');
  }
  ngOnInit() {
    this.createWidget(connectPagination, {
      // instance options
    });
    super.ngOnInit();
  }
}

3. Render from the state

Your component instance has access to a this.state property which holds the rendering options of the widget.

public state: PaginationWidgetDescription['renderState'];
// {
//   pages: number[];
//   currentRefinement: number;
//   nbHits: number;
//   nbPages: number;
//   isFirstPage: boolean;
//   isLastPage: boolean;
//   refine: Function;
//   createURL: Function;
//   widgetParams: Function;
// }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<button
  (click)="state.refine(state.currentRefinement - 1)"
  [disabled]="state.isFirstPage"
>
  Prev
</button>
<button *ngFor="let page of state.pages" (click)="state.refine(page)">
  <strong *ngIf="page === state.currentRefinement">{{ page + 1 }}</strong>
  <span *ngIf="page !== state.currentRefinement">{{ page + 1 }}</span>
</button>
<button
  (click)="state.refine(state.currentRefinement + 1)"
  [disabled]="state.isLastPage"
>
  Next
</button>

If SEO is critical to your search page, your custom HTML markup needs to be parsable:

  • use plain <a> tags with href attributes for search engines bots to follow them,
  • use semantic markup with structured data when relevant, and test it.

Refer to our SEO checklist for building SEO-ready search experiences.

Rendering options

Parameter Description
pages
type: number[]

The pages relevant to the current state and padding.

currentRefinement
type: number

The number of the currently displayed page.

nbHits
type: number

The computed number of hits for the last query (can be approximate).

nbPages
type: number

The number of pages for the result set.

isFirstPage
type: boolean

Whether the current page is also the first one.

isLastPage
type: boolean

Whether the current page is also the last one.

refine
type: function

Sets the current page and triggers a search.

createURL
type: function

Generates a URL for the next state. The number is the page to generate the URL for.

widgetParams
type: function

All original widget options forwarded to the render function.

Instance options

Parameter Description
totalPages
type: number
Optional

The total number of pages to browse.

padding
type: number
default: 3
Optional

The padding of pages to show around the current page.

Full example

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
import { Component, Inject, forwardRef, Optional } from '@angular/core';
import { TypedBaseWidget, NgAisInstantSearch, NgAisIndex } from 'angular-instantsearch';

import connectPagination, {
  PaginationWidgetDescription,
  PaginationConnectorParams
} from 'instantsearch.js/es/connectors/pagination/connectPagination';

@Component({
  selector: 'app-pagination',
  template: `
<button
  (click)="state.refine(state.currentRefinement - 1)"
  [disabled]="state.isFirstPage"
>
  Prev
</button>
<button *ngFor="let page of state.pages" (click)="state.refine(page)">
  <strong *ngIf="page === state.currentRefinement">{{ page + 1 }}</strong>
  <span *ngIf="page !== state.currentRefinement">{{ page + 1 }}</span>
</button>
<button
  (click)="state.refine(state.currentRefinement + 1)"
  [disabled]="state.isLastPage"
>
  Next
</button>
`
})
export class Pagination extends TypedBaseWidget<PaginationWidgetDescription, PaginationConnectorParams> {
  public state: PaginationWidgetDescription['renderState']; // Rendering options
  constructor(
    @Inject(forwardRef(() => NgAisIndex))
    @Optional()
    public parentIndex: NgAisIndex,
    @Inject(forwardRef(() => NgAisInstantSearch))
    public instantSearchInstance: NgAisInstantSearch
  ) {
    super('Pagination');
  }
  ngOnInit() {
    this.createWidget(connectPagination, {
      // instance options
    });
    super.ngOnInit();
  }
}
Did you find this page helpful?