ais-hierarchical-menu
You are reading the documentation for Angular InstantSearch v3, which is in beta. You can find the v2 documentation here.
<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
The minimum number of items to diplayed. |
||
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: x => x
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 mapping over the items to transform, and remove or reorder them. |
||
Copy
|
Customize the UI - connectHierarchicalMenu
If you want to create your own UI of the ais-hierarchical-menu
widget, you can combine the connectHierarchicalMenu
connector with the BaseWidget
class.
1. Extend the BaseWidget
class
First of all, you will need to write some boilerplate code in order to initialize correctly the BaseWidget
class. This happens in the constructor()
of your class extending the BaseWidget
class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Component, Inject, forwardRef } from '@angular/core';
import { BaseWidget, NgAisInstantSearch } from 'angular-instantsearch';
@Component({
selector: 'app-hierarchical-menu',
template: '<p>It works!</p>'
})
export class HierarchicalMenu extends BaseWidget {
constructor(
@Inject(forwardRef(() => NgAisInstantSearch))
public instantSearchParent
) {
super('HierarchicalMenu');
}
}
There are a couple of things happening in this boilerplate:
- we create a
HierarchicalMenu
class extendingBaseWidget
- we reference the
<ais-instantsearch>
parent component instance on theHierarchicalMenu
widget class - we 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 BaseWidget
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
import { Component, Inject, forwardRef } from '@angular/core';
import { BaseWidget, NgAisInstantSearch } from 'angular-instantsearch';
import { connectHierarchicalMenu } from 'instantsearch.js/es/connectors';
@Component({
selector: 'app-hierarchical-menu',
template: '<p>It works!</p>'
})
export class HierarchicalMenu extends BaseWidget {
public state: {
// render options
};
constructor(
@Inject(forwardRef(() => NgAisInstantSearch))
public instantSearchParent
) {
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: {
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 or not the list is expanded. |
canToggleShowMore
|
type: boolean
Whether or not 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
The minimum number of facet values to retrieve. |
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 mapping over the items to transform, and remove or reorder them. |
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
import { Component, Inject, forwardRef } from '@angular/core';
import { BaseWidget, NgAisInstantSearch } from 'angular-instantsearch';
import { connectHierarchicalMenu } from 'instantsearch.js/es/connectors';
@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 BaseWidget {
public state: {
items: object[];
isShowingMore: boolean;
canToggleShowMore: boolean;
refine: Function;
toggleShowMore: Function;
createURL: Function;
widgetParams: object;
};
constructor(
@Inject(forwardRef(() => NgAisInstantSearch))
public instantSearchParent
) {
super('HierarchicalMenu');
}
ngOnInit() {
this.createWidget(connectHierarchicalMenu, {
// instance options
attributes: ['hierarchicalCategories.lvl0', 'hierarchicalCategories.lvl1', 'hierarchicalCategories.lvl2'],
});
super.ngOnInit();
}
}
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>