ais-hierarchical-menu
<ais-hierarchical-menu [attributes]="string[]" // Optional parameters [limit]="number" separator="string" rootPath="string" [showParentLevel]="boolean" [sortBy]="string[]|function" [autoHideContainer]="boolean" [transformItems]="function" ></ais-hierarchical-menu>
About this widget
The ais-hierarchical-menu
component displays a tree menu that lets the user browse attributes.
Requirements
The objects to use in the hierarchical menu must follow this structure:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
{
"objectID": "321432",
"name": "lemon",
"hierarchicalCategories.lvl0": "products",
"hierarchicalCategories.lvl1": "products > fruits"
},
{
"objectID": "8976987",
"name": "orange",
"hierarchicalCategories.lvl0": "products",
"hierarchicalCategories.lvl1": "products > fruits"
}
]
It’s also possible to provide more than one path for each level:
1
2
3
4
5
6
7
8
[
{
"objectID": "321432",
"name": "lemon",
"hierarchicalCategories.lvl0": ["products", "goods"],
"hierarchicalCategories.lvl1": ["products > fruits", "goods > to eat"]
}
]
The attributes passed to the attributes
prop must be declared as Attributes for faceting on the Algolia dashboard or configured as attributesForFaceting
with the Algolia API.
Examples
1
2
3
4
5
6
7
<ais-hierarchical-menu
[attributes]="[
'hierarchicalCategories.lvl0',
'hierarchicalCategories.lvl1',
'hierarchicalCategories.lvl2'
]"
></ais-hierarchical-menu>
Props
attributes
|
type: string[]
Required
The name of the attributes to generate the menu with. |
||
Copy
|
|||
limit
|
type: number
default: 10
Optional
How many facet values to retrieve. |
||
Copy
|
|||
separator
|
type: string
default: >
Optional
The level separator used in the records. |
||
Copy
|
|||
rootPath
|
type: string
Optional
The path to use if the first level is not the root level. |
||
Copy
|
|||
showParentLevel
|
type: string
default: true
Optional
Whether to show the siblings of the selected parent level of the current refined value. |
||
Copy
|
|||
sortBy
|
type: string[]|function
default: ["name:asc"]
Optional
How to sort refinements. Must be one or more of the following strings:
It’s also possible to give a function, which must have the same signature than the JavaScript |
||
Copy
|
|||
autoHideContainer
|
type: boolean
Optional
Hides the hierarchical menu if there’s no item to display. |
||
Copy
|
|||
transformItems
|
type: function
default: items => items
Optional
Receives the items and is called before displaying them. Should return a new array with the same shape as the original array. Useful for transforming, removing, or reordering items. In addition, the full |
||
Copy
|
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
29
30
<div class="ais-HierarchicalMenu">
<ul class="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--lvl0">
<li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent ais-HierarchicalMenu-item--selected">
<a class="ais-HierarchicalMenu-link" href="#">
<span class="ais-HierarchicalMenu-label">Appliances</span>
<span class="ais-HierarchicalMenu-count">4,306</span>
</a>
<ul class="ais-HierarchicalMenu-list ais-HierarchicalMenu-list--child ais-HierarchicalMenu-list--lvl1">
<li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent">
<a class="ais-HierarchicalMenu-link" href="#">
<span class="ais-HierarchicalMenu-label">Dishwashers</span>
<span class="ais-HierarchicalMenu-count">181</span>
</a>
</li>
<li class="ais-HierarchicalMenu-item">
<a class="ais-HierarchicalMenu-link" href="#">
<span class="ais-HierarchicalMenu-label">Fans</span>
<span class="ais-HierarchicalMenu-count">91</span>
</a>
</li>
</ul>
</li>
<li class="ais-HierarchicalMenu-item ais-HierarchicalMenu-item--parent">
<a class="ais-HierarchicalMenu-link" href="#">
<span class="ais-HierarchicalMenu-label">Audio</span>
<span class="ais-HierarchicalMenu-count">1,570</span>
</a>
</li>
</ul>
</div>
Customize the UI with connectHierarchicalMenu
If you want to create your own UI of the ais-hierarchical-menu
widget, you can combine the connectHierarchicalMenu
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-hierarchical-menu',
template: '<p>It works!</p>'
})
export class HierarchicalMenu extends TypedBaseWidget {
constructor(
@Inject(forwardRef(() => NgAisIndex))
@Optional()
public parentIndex: NgAisIndex,
@Inject(forwardRef(() => NgAisInstantSearch))
public instantSearchInstance: NgAisInstantSearch
) {
super('HierarchicalMenu');
}
}
There are a couple of things happening in this boilerplate:
- create a
HierarchicalMenu
class extendingTypedBaseWidget
- reference the
<ais-instantsearch>
parent component instance on theHierarchicalMenu
widget class - set
app-hierarchical-menu
as a selector, so we can use our component as<app-hierarchical-menu></app-hierarchical-menu>
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
31
import { Component, Inject, forwardRef, Optional } from '@angular/core';
import { TypedBaseWidget, NgAisInstantSearch, NgAisIndex } from 'angular-instantsearch';
import connectHierarchicalMenu, {
HierarchicalMenuWidgetDescription,
HierarchicalMenuConnectorParams
} from 'instantsearch.js/es/connectors/hierarchical-menu/connectHierarchicalMenu';
@Component({
selector: 'app-hierarchical-menu',
template: '<p>It works!</p>'
})
export class HierarchicalMenu extends TypedBaseWidget<HierarchicalMenuWidgetDescription, HierarchicalMenuConnectorParams> {
public state: HierarchicalMenuWidgetDescription['renderState']; // Rendering options
constructor(
@Inject(forwardRef(() => NgAisIndex))
@Optional()
public parentIndex: NgAisIndex,
@Inject(forwardRef(() => NgAisInstantSearch))
public instantSearchInstance: NgAisInstantSearch
) {
super('HierarchicalMenu');
}
ngOnInit() {
this.createWidget(connectHierarchicalMenu, {
// instance options
attributes: ['hierarchicalCategories.lvl0', 'hierarchicalCategories.lvl1', 'hierarchicalCategories.lvl2'],
});
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: HierarchicalMenuWidgetDescription['renderState'];
// {
// items: object[];
// isShowingMore: boolean;
// canToggleShowMore: boolean;
// refine: Function;
// toggleShowMore: Function;
// createURL: Function;
// widgetParams: object;
// }
1
2
3
4
5
6
7
8
9
10
11
<div *ngFor="let item of state.items">
<!-- level 0 -->
<label>
<input type="checkbox"
(click)="state.refine(item.value)"
[checked]="item.isRefined" > {{ item.label }} ({{ item.count }})
</label>
<div *ngFor="let subitem of item.data">
<!-- level 1 ... -->
</div>
</div>
If SEO is critical to your search page, your custom HTML markup needs to be parsable:
- use plain
<a>
tags withhref
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
items
|
type: object[]
The list of available items, with each item:
|
isShowingMore
|
type: boolean
Whether the list is expanded. |
canToggleShowMore
|
type: boolean
Whether the “Show more” button can be clicked. |
refine
|
type: function
Sets the path of the hierarchical filter and triggers a new search. |
toggleShowMore
|
type: function
Toggles the number of displayed values between |
createURL
|
type: function
Generates a URL for the next state. |
widgetParams
|
type: object
All original widget options forwarded to the render function. |
Instance options
attributes
|
type: string[]
Required
The name of the attributes to generate the menu with. |
limit
|
type: number
default: 10
Optional
How many facet values to retrieve. When isShowingMore is |
showMoreLimit
|
type: number
Optional
The maximum number of displayed items (only used when the |
separator
|
type: string
default: >
Optional
The level separator used in the records. |
rootPath
|
type: string
default: null
Optional
The prefix path to use if the first level is not the root level. |
showParentLevel
|
type: boolean
default: true
Optional
Whether to show the siblings of the selected parent level of the current refined value. |
sortBy
|
type: string[]|function
default: ["name:asc"]
Optional
How to sort refinements. Must be one or more of the following strings:
It’s also possible to give a function, which receives items two by two, like JavaScript’s |
transformItems
|
type: function
default: items => items
Optional
Receives the items and is called before displaying them. Should return a new array with the same shape as the original array. Useful for transforming, removing, or reordering items. In addition, the full |
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
import { Component, Inject, forwardRef, Optional } from '@angular/core';
import { TypedBaseWidget, NgAisInstantSearch, NgAisIndex } from 'angular-instantsearch';
import connectHierarchicalMenu, {
HierarchicalMenuWidgetDescription,
HierarchicalMenuConnectorParams
} from 'instantsearch.js/es/connectors/hierarchical-menu/connectHierarchicalMenu';
@Component({
selector: 'app-hierarchical-menu',
template: `
<div *ngFor="let item of state.items">
<!-- level 0 -->
<label>
<input type="checkbox"
(click)="state.refine(item.value)"
[checked]="item.isRefined" > {{ item.label }} ({{ item.count }})
</label>
<div *ngFor="let subitem of item.data">
<!-- level 1 ... -->
</div>
</div>
`
})
export class HierarchicalMenu extends TypedBaseWidget<HierarchicalMenuWidgetDescription, HierarchicalMenuConnectorParams> {
public state: HierarchicalMenuWidgetDescription['renderState']; // Rendering options
constructor(
@Inject(forwardRef(() => NgAisIndex))
@Optional()
public parentIndex: NgAisIndex,
@Inject(forwardRef(() => NgAisInstantSearch))
public instantSearchInstance: NgAisInstantSearch
) {
super('HierarchicalMenu');
}
ngOnInit() {
this.createWidget(connectHierarchicalMenu, {
// instance options
attributes: ['hierarchicalCategories.lvl0', 'hierarchicalCategories.lvl1', 'hierarchicalCategories.lvl2'],
});
super.ngOnInit();
}
}