<<<<<<< HEAD
A lightweight, declarative and configurable breadcrumbs solution for Angular 6 and beyond. https://www.npmjs.com/package/my-xng
A lightweight, declarative and dynamic breadcrumbs solution for Angular 6 and beyond. https://www.npmjs.com/package/xng-breadcrumb
- In applications with deep navigation hierarchy, it is essential to have breadcrumbs.
- Breadcrumbs easily allow going back to states higher up in the hierarchy.
Live Demo - A demo app showcasing my-xng
usage in an Angular app. Navigate through different links to see breadcrumbs behavior.
<<<<<<< HEAD
- ✅ Zero configuration: Just add
<my-xng></my-xng>
anywhere in the app. Breadcrumb labels will be auto-generated by analyzing Angular Route configuration in your App. =======
- ✅ Zero configuration: Just add
<xng-breadcrumb></xng-breadcrumb>
anywhere in the app. Breadcrumb labels are auto-generated by analyzing Angular Route configuration in your App.
b31cb894c3840682f98af3c97d07b45524e205ff
-
✅ Custom labels: Each route can have a custom label defined via Angular Route Config. The labels will be picked automatically while forming breadcrumbs.
-
✅ Update labels dynamically: Change breadcrumbs dynamically using
BreadcrumbService.set()
. You can either use route path or path alias to change breadcrumb for a route. -
✅ Skip breadcrumb: Skip specific routes from displaying in breadcrumbs, conditionally.
-
✅ Disable breadcrumb: Disable specific routes so that navigation is disbaled to intermediate routes.
-
✅ Customization: Customize breadcrumb template to show icons with label, use pipes on text, add i18n with ngx-translate, etc.
-
✅ Styling: Separator and Styles can be customized with ease.
-
✅ QueryParams and Fragment: Preserves QueryParams and Fragemnet while navigating via breadcrumbs
<<<<<<< HEAD
- Install via npm or yarn
npm install --save my-xng
//------------- OR --------------
yarn add my-xng
- Import 'BreadcrumbModule' in your Application
import {BreadcrumbModule} from 'my-xng';
@NgModule({
...
imports: [BreadcrumbModule],
...
})
export class AppModule { }
- Add 'my-xng' selector, wherever you plan to show breadcrumbs
<my-xng></my-xng>
- (Optional) Use BreadcrumbService, if you want to change breadcrumbs behavior(visibility, label, etc) dynamically.
import { BreadcrumbService } from 'my-xng';
constructor(private breadcrumbService: BreadcrumbService) {}
// Code examples with BreadcrumbService are given below, under Usage section
🎉🎉 That's it. You should see auto-generated breadcrumbs appearing for each route.
Note: XngBreadcrumb has a peer dependency on @angular/router
. Include RouterModule
in App imports, if you haven't already.
my-xng | Angular |
---|---|
4.x.x | 6.x, 7.x |
6.x.x | 8.x, 9.x, 10.x |
- define 'breadcrumb' within the data property of route.
- a 'breadcrumb' can be defined as a string OR object OR function.
- Use breadcrumb as a string if you are just providing breadcrumb text
- Use breadcrumb as an object if you are providing additional properties like 'alias', 'skip', 'info', 'disable'. In you define breadcrumb as an object, label property denotes breadcrumb text.
- Use breadcrumb as a function if you want to alter the auto-generated label as needed.
{
path: 'dashboard',
loadChildren: './dashboard/dashboard.module#DashboardModule',
data: { breadcrumb: 'Home' }
},
{
path: 'add',
component: MentorAddComponent,
data: { breadcrumb: 'New' }
}
{
path: 'dashboard',
loadChildren: './dashboard/dashboard.module#DashboardModule',
data: {
breadcrumb: {
label: 'Home',
info: { myData: { icon: 'home', iconType: 'material' } }
}
}
},
{
path: 'add',
component: MentorAddComponent,
data: { breadcrumb: { skip: true, alias: 'mentorAdd' } }
}
{
path: '/orders',
children: [{
':id',
data: {
breadcrumb: (resolvedId: string) => `Viewing ${resolvedId} now`
}
}]
}
- Breadcrumb label can be updated dynamically using route path or alias
- For simple routes, route path is enough. Ex:
breadcrumbService.set(<route path> , <breadcrumb label>)
- For long deep routes, you can use alias instead.
- Create an alias for a route in route config. Prefix alias with '@' while using the set() method. Ex:
breadcrumbService.set(@<alias> , <breadcrumb label>)
{
path: 'mentors',
component: MentorListComponent,
children: [
{
path: ':id',
component: MentorDetailsComponent
}
]
}
// routepath can contain path params similar to how you define in routes
breadcrumbService.set('mentors', 'Mentor View'); // path for MentorListComponent
breadcrumbService.set('mentor/:id', 'Uday Vunnam'); // path for MentorDetailsComponent contains param (:id)
{
path: 'mentors',
component: MentorListComponent,
children: [
{
path: ':id',
component: MentorDetailsComponent
data: {
breadcrumb: {
alias: 'mentorName'
}
}
}
]
}
breadcrumbService.set('@mentorName', 'Uday Vunnam');
You can skip a route from displaying in breadcrumbs in two ways
- make skip: true in route config
breadcrumb: { skip: true }
- dynamically skip using
set(<myPathOrAlias>, { skip:true })
;
{
path: 'edit',
component: MentorEditComponent,
data: { breadcrumb: { skip: true } }
}
breadcrumbService.set('mentor/:id/edit', { skip: true });
breadcrumbService.set('@mentorName', { skip: true }); // using alias '@mentorName'
//To make a hidden breadcrumb visible.
breadcrumbService.set('mentor/:id/edit', { skip: false });
breadcrumbService.set('@mentorName', { skip: false }); // using alias '@mentorName'
You can show an intermediate breadcrumb, but disable navigation if the route has no meaning.
- make disable: true in route config
breadcrumb: { disable: true }
- dynamically skip using
set(<myPathOrAlias>, { disable:true })
;
You can display whatever you want in the place of breadcrumb text by providing a custom template.
- Use *xngBreadcrumbItem directive to provide a custom template
- breadcrumb label is available implicitly in the template context
{
path: '',
pathMatch: 'full',
component: HomeComponent,
data: {
breadcrumb: 'app home'
}
}
<my-xng>
<ng-container *xngBreadcrumbItem="let breadcrumb">
<ng-container>{{ breadcrumb | titlecase }}</ng-container>
</ng-container>
</my-xng>
- define 'info' associated with breadcrumb in route config. 'info' has type . you can pass string or object as you need.
- 'info' is available in the context of *xngBreadcrumbItem.
- Additionally 'first', 'last', 'index' and count are passed to identify the respective items.
{
path: '',
pathMatch: 'full',
component: HomeComponent,
data: {
breadcrumb: {
label: 'app home',
info: 'home'
}
}
}
<my-xng>
<ng-container
*xngBreadcrumbItem="let breadcrumb; let info = info; let first = first"
>
<mat-icon *ngIf="info">{{ info }}</mat-icon>
<ng-container *ngIf="!first">{{ breadcrumb }}</ng-container>
</ng-container>
</my-xng>
- Usually, internationalization is achieved in Angular using libraries like ngx-translate or transloco.
- These libraries provide a pipe to change text while language is changed.
- For example, if you are using ngx-translate you can change the language for breadcrumb text as shown below.
<my-xng>
<ng-container *xngBreadcrumbItem="let breadcrumb">
<ng-container>{{ breadcrumb | translate }}</ng-container>
</ng-container>
</my-xng>
- Breadcrumb uses '/' as the separator by default.
- To use custom separator pass separator as an input to
<my-xng>
. - You can either use a simple string(>>, -, -->) or a component (mat-icon, fa-icon) as a separator.
<my-xng separator=">"></my-xng>
<my-xng [separator]="iconTemplate"></my-xng>
<ng-template #iconTemplate>
<mat-icon>arrow_right</mat-icon>
</ng-template>
-
<my-xng>
defines the least possible specificity for selectors, to make it easy to override them. -
override styles by changing the CSS for corresponding classes. (Keep this styles in app root styles file if you don't want to use ::ng-deep)
-
Below is a visualization of various classes involved in my-xng to help you for easy identification.
-
(Optional) my-xng takes 'class' as input. This class will be applied to the root of the breadcrumb. This can be used to increase specificity when there are conflicting styles.
.my-xng-root {
padding: 8px 16px;
display: inline-block;
border-radius: 4px;
background-color: #e7f1f1;
}
.my-xng-separator {
padding: 0 4px;
}
- Breadcrumbs are integrated with Angular Router and labels are auto-generated (if a label is not provided for a route).
- Auto-generated label is the same as route the path segment.
- If you want to disable this behavior, set
[autoGenerate]=false
.
<my-xng [autoGenerate]="false"></my-xng>
When we have conditional routing in App components (Ex: for a certain role navigate to pathA vs pathB from a component), it might be useful to have conditional routing from breadcrumb too
- With App's RouteConfig: Provide routeInterceptor callback in RouteConfig if you know the redirection logic upfront
{
path: '',
pathMatch: 'full',
component: HomeComponent,
data: {
breadcrumb: {
label: 'my home',
info: 'home',
routeInterceptor: (routeLink, breadcrumb)=> {
console.log(routeLink);
return routeLink;
}
},
},
}
- With Breadcrumb service: If you want to access Application context within the interceptor, use breadcrumbService that can be called from anywhere in the App
const isDesigner = true;
breadcrumbService.set('home', {
routeInterceptor: (routeLink, breadcrumb) =>
isDesigner ? '/designer' : routeLink,
});
property | Description | Type | Default |
---|---|---|---|
breadcrumb | Breadcrumb data provided in App route config | `string | Breadcrumb |
breadcrumb: {alias} | alias name for a route | string |
undefined |
breadcrumb: {skip} | skip a route from showing in breadcrumbs | boolean |
false |
breadcrumb: {disable} | disable navigation for a breadcrumb item | boolean |
false |
breadcrumb: {info} | arbitrary info for a breadcrumb. | `string | object` |
breadcrumb: {label} | same as breadcrumb. Use label if breadcrumb is defined as object | string |
undefined |
Input | Description | Type | Default |
---|---|---|---|
separator | input: separator between breadcrumbs | `string | TemplateRef` |
autoGenerate | input:whether to auto generate breadcrumb labels | boolean |
true |
*xngBreadcrumbItem | directive: to read context in custom breadcrumb templates | NA | NA |
preserveQueryParams | preserve query params while navigating via breadcrumbs | boolean |
true |
preserveFragment | preserve fragment while navigating via breadcrumbs | boolean |
true |
argument | Description | Type |
---|---|---|
pathOrAlias | full route path or alias prefixed with '@' | string |
breadcrumb | breadcrumb data to update for a route | `string |
- For the same route path, you can define breadcrumbs either on parent or any descendant with empty path.
- If both are defined, the children take the precedence.
// defining breadcrumb on Component Route
{
path: ':userId',
data: { breadcrumb: 'Declared on Parent Component' },
children: [
{ path: '', component: ShowUserComponent }
]
}
// defining breadcrumb on children with empty path
{
path: ':userId',
children: [
{ path: '', component: ShowUserComponent, data: { breadcrumb: 'Declaraed on child with empty path' }
]
}
// defining breadcrumb on Module route
{ path: 'home', loadChildren: './home/home.module#HomeModule', data: { breadcrumb: 'Declaraed on Parent Module' } }
// Within HomeModule Routes -
{ path: '', pathMatch: 'full', component: HomeComponent, data: { breadcrumb: 'Declaraed on child with empty path' }}
- A
<nav>
witharia-label="breadcrumb"
identifies type of navigation as breadcrumb by screen readers. - The breadcrumb links are structured using an ordered list
<ol>
. - The last
<li>
element represents the current page, so it doesn't have to be clickable. - Separators between links have
aria-hidden=true
. This prevents the screen reader announcement of visual separators.
This project was generated using Nx.
If you wish to contribute to this repository, below are the steps for local development.
- Clone the repository
git clone https://github.com/udayvunnam/my-xng.git
- Run
yarn
to install the dependencies - Run
yarn start
to build and watch both the library and the demo app. This opens the demo app athttp://localhost:4200/
automatically.
Run yarn build
to build the library and demo app together. The build artifacts will be stored in the dist/
directory.
This step is used by CircleCI to build both the library and the demo app. After a successful build, the two demo apps are deployed to Netlify.
Run yarn release
on main branch if you wish to publish a new version of library to npm
This ingternally uses standard-version to
- bump the library version based on the commits
- generates changelog
- commit bump files and changelog
- create a new tag with the new version number
CircleCI gets notified on every new tag push and publishes the library if build and tests are success
=======
- ✅ SSR: Supports server side rendering with nguniversal
b31cb894c3840682f98af3c97d07b45524e205ff
Thanks goes to these wonderful people (emoji key):
<<<<<<< HEAD
=======
Uday Vunnam 💻 📖 🚧 |
anthonythiry 💻 |
dedrazer 💻 |
Danny Feliz 📖 |
<<<<<<< HEAD
ng add my-xng
``` -->
=======
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
>>>>>>> b31cb894c3840682f98af3c97d07b45524e205ff