@exalif/ngx-breadcrumbs
Version:
Angular 4+ breadcrumbs on top of native Angular router
332 lines (267 loc) • 8.54 kB
Markdown
# /ngx-breadcrumbs
An Angular (4+) module generating breadcrumbs based on the routing state.
This package is a modified fork of original [ngx-breadcrumbs](https://github.com/McNull/ngx-breadcrumbs) package by McNull
## Requirements
**Caution**: Version **>=9.0.0** requires:
- `rxjs` **>=6.3.0**
- `` **>=9.0.0**
*note*: lodash is not required anymore on this version
**Caution**: Version **>=8.0.0** requires:
- `rxjs` **>=6.3.0**
- `` **>=9.0.0**
- you must install `lodash.template` as a dependency in your project as it was moved to peer dependency on this version
**Caution**: Version **>=7.0.0** requires:
- `rxjs` **>=6.3.0**
- `` **>=7.0.0**
**Caution**: Version **>=6.0.0** requires:
- `rxjs` **>=6.0.0**
- `` **>=6.0.0**
## Installation
```bash
# install via npm
$ npm --save install /ngx-breadcrumbs
```
```bash
# install via yarn
$ yarn add /ngx-breadcrumbs
```
## Usage
Import the `BreadcrumbsModule` in your root module (`app.module.ts`) after
importing the _router_ module.
You can provide an initial `BreadcrumbsConfig` as `forRoot` argument. By default, if no config is provided, the applied config will correspond to the one provided in the following example:
```typescript
import { RouterModule } from '/router';
import { BreadcrumbsModule } from '/ngx-breadcrumbs';
({
imports: [
RouterModule.forRoot(myRoutes),
BreadcrumbsModule.forRoot({
postProcess: null,
applyDistinctOn: 'text',
}),
],
})
export class AppModule {}
```
Place the `lib-breadcrumbs` component, which will render the breadcrumbs,
somewhere in your markup.
```typescript
({
selector: 'app-root',
template: `
<div class="container">
<lib-breadcrumbs></lib-breadcrumbs>
<router-outlet></router-outlet>
</div>`
})
export class AppComponent {}
```
Usage of the `lib-breadcrumbs` render component is optional. If a different
markup output is desired, a custom component can be created that subscribes to
the `BreadcrumbsService.crumbs$` observable (also available through method `BreadcrumbsService.getCrumbs()`).
### Routing Configuration
Breadcrumbs links are generated based on the route configuration. If a route
entry contains a `data.breadcrumbs` property the _breadcrumbs service_ assumes
breadcrumbs should be created whenever this route or one its child routes are
active.
```typescript
const myRoutes : Route[] = {
{
path: '',
component: HomeComponent,
data: {
// Uses static text (Home)
breadcrumbs: 'Home'
}
},
{
path: 'about',
component: AboutComponent,
data: {
// Uses last urlfragment (about) as text
breadcrumbs: true
}
},
{
path: 'person',
data: {
// Uses text property (Person)
breadcrumbs: true,
text: 'Person'
},
children: [
{
path: '',
component: PersonListComponent
},
{
path: ':id',
component: PersonDetailComponent,
data: {
// Interpolates values resolved by the router
breadcrumbs: '{{ person.name }}'
},
resolve: {
person: PersonResolver
}
}
]
},
{
path: 'folder',
data: {
// Uses static text 'Folder'
breadcrumbs: 'Folder'
},
children: [
{
path: '',
component: FolderComponent
},
{
path: ':id',
component: FolderComponent,
data: {
// Resolves the breadcrumbs for this route by
// implementing a BreadcrumbsResolver class.
breadcrumbs: FolderBreadcrumbsResolver
}
}
]
}
};
```
### API
#### Breadcrumb
The `Breadcrumb` interface defines the properties of the breadcrumb items.
```typescript
export interface Breadcrumb {
text: string, // The text to display
path: string // The associated path
}
```
#### BreadcrumbsComponent
The component simply renders the list of the `Breadcrumb` items provided by the `BreadcrumbsService`.
A custom breadcrumb component is easily created by injecting the breadcrumb
service and iterating over the breadcrumb items.
##### Styling
The following CSS classes can be used for styling purpose:
* `breadcrumbs__container`: `ol` list container
* `breadcrumbs__item`: each breadcrum `li` element
* `breadcrumbs__item--active`: added on last `li` element (current active link)
Each breadcrumb `li` element contains a `a` link and a `span` text element.
#### BreadcrumbsService
The service has one public property `crumbs$`. It's an observable stream of
`Breadcrumb[]`, which is updated after each route change.
#### BreadcrumbsResolver
If needed, a custom resolver can be implemented which is activated whenever a
certain route becomes active. This can be useful whenever the route
configuration cannot match the desired breadcrumb hierachy.
The signature of the resolver implements `Resolve<T>` from the
[Angular Router](https://angular.io/api/router/Resolve) and needs to resolve an
array of `Breadcrumb` items.
To associate a route with a certain resolver, its breadcrumbs data property in
the route configuration should point to the resolver:
```typescript
const myRoutes = [
{
path: 'somepath',
component: SomeComponent,
data: {
breadcrumbs: MyBreadcrumbsResolver
}
}
];
```
##### Members
```typescript
// Should resolve zero or more Breadcrumb items.
public function resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
: Observable<T> | Promise<T> | T
```
```typescript
// Helper function that returns the full path for the provided route snapshot.
public function getFullPath(route: ActivatedRouteSnapshot)
: string
```
To access parent member without redeclaring method, use `super`. e.g: `super.getFullPath(route)`.
##### Example using a custom resolver and custom Breadcrumb interface
```typescript
export interface MyBreadcrumb extends Breadcrumb {
icon?: string;
}
()
export class MyBreadcrumbsResolver extends BreadcrumbsResolver {
// Optional: inject any required dependencies
constructor(private myService: MyService) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): MyBreadcrumb[] {
const myFolderId = route.params.id;
const icon: string = route.data.icon ? route.data.icon : null;
const myCrumbs =
this.myService.getFolders(myFolderId).pipe(
.map((folder) => ({
text: folder.title,
icon
path: super.getFullPath(route.parent) + '/' + folder.id
}));
return myCrumbs;
}
}
```
*Note*: the resolve method must return one of the following types:
* `Breadcrumb[]`
* `Observable<Breadcrumb[]>`
* `Promise<Breadcrumb>`
#### BreadcrumbsConfig
The configuration of the breadcrumbs module.
##### Members
**postProcess**
Callback function with the following signature:
```typescript
function (crumbs: Breadcrumb[]): Promise<Breadcrumb[]> | Observable<Breadcrumb[]> | Breadcrumb[];
```
Can be used to make custom changes to the breadcrumb array after the service
has constructed the breadcrumb trail.
Example:
```typescript
({
/* ... */
})
export class AppModule {
constructor(breadcrumbsConfig: BreadcrumbsConfig) {
breadcrumbsConfig.postProcess = (breadcrumbs): Breadcrumb[] => {
// Ensure that the first breadcrumb always points to home
let processedBreadcrumbs = breadcrumbs;
if(breadcrumbs.length && breadcrumbs[0].text !== 'Home') {
processedBreadcrumbs = [
{
text: 'Home',
path: ''
}
].concat(breadcrumbs);
}
return processedBreadcrumbs;
};
}
}
```
**applyDistinctOn**
By default, `distinct` rxjs operator is applied on `text` key of `Breadcrumb`, not to add crumbs with same text in the breadcrumbs array. If this is not correct behavior in your app, you can change `applyDistinctOn` key to another `Breadcrumb` key or to `null` to disable this behavior.
Signature:
```typescript
applyDistinctOn: DistinctKey | null = 'text';
```
Usage example to remove `distinct` behavior:
```typescript
import { RouterModule } from '/router';
import { BreadcrumbsModule } from '/ngx-breadcrumbs';
({
imports: [
RouterModule.forRoot(myRoutes),
BreadcrumbsModule.forRoot({
applyDistinctOn: null,
}),
],
})
export class AppModule {}
```