Skip to content

A lightweight, configurable and reactive breadcrumbs for Angular 2+

License

Notifications You must be signed in to change notification settings

souryvath/xng-breadcrumb

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

my-xng

<<<<<<< HEAD

A lightweight, declarative and configurable breadcrumbs solution for Angular 6 and beyond. https://www.npmjs.com/package/my-xng

npm version bundle size license npm downloads

CircleCI

A lightweight, declarative and dynamic breadcrumbs solution for Angular 6 and beyond. https://www.npmjs.com/package/xng-breadcrumb

CircleCI npm version bundle size license

npm downloads

b31cb894c3840682f98af3c97d07b45524e205ff Twitter follow

About

  • In applications with deep navigation hierarchy, it is essential to have breadcrumbs.
  • Breadcrumbs easily allow going back to states higher up in the hierarchy.

Demo

Live Demo - A demo app showcasing my-xng usage in an Angular app. Navigate through different links to see breadcrumbs behavior.

<<<<<<< HEAD

my-xng usage

Features

  • 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. ======= xng-breadcrumb usage

Documentation

Documentation

Features

  • 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

Quickstart

  1. Install via npm or yarn
npm install --save my-xng
//------------- OR --------------
yarn add my-xng
  1. Import 'BreadcrumbModule' in your Application
import {BreadcrumbModule} from 'my-xng';
@NgModule({
  ...
  imports: [BreadcrumbModule],
  ...
})
export class AppModule { }
  1. Add 'my-xng' selector, wherever you plan to show breadcrumbs
<my-xng></my-xng>
  1. (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.

Angular Version Compatibility

my-xng Angular
4.x.x 6.x, 7.x
6.x.x 8.x, 9.x, 10.x

Setup Guide

Custom breadcrumb labels via Angular Route Config

  • 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.

breadcrumb as a string

  {
    path: 'dashboard',
    loadChildren: './dashboard/dashboard.module#DashboardModule',
    data: { breadcrumb: 'Home' }
  },
  {
    path: 'add',
    component: MentorAddComponent,
    data: { breadcrumb: 'New' }
  }

breadcrumb as an object

  {
    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' } }
  }

breadcrumb as a function

{
  path: '/orders',
  children: [{
    ':id',
    data: {
      breadcrumb: (resolvedId: string) => `Viewing ${resolvedId} now`
    }
  }]
}

Update labels dynamically

  • 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>)

using route path to update labels dynamically

  {
    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)

using alias to update labels dynamically

  {
    path: 'mentors',
    component: MentorListComponent,
    children: [
      {
        path: ':id',
          component: MentorDetailsComponent
          data: {
            breadcrumb: {
              alias: 'mentorName'
            }
          }
        }
    ]
  }

  breadcrumbService.set('@mentorName', 'Uday Vunnam');

Skip Breadcrumbs for certain route path

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 });

skip breadcrumb in route config

  {
    path: 'edit',
    component: MentorEditComponent,
    data: { breadcrumb: { skip: true } }
  }

skip breadcrumb dynamically

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'

Dibsable Breadcrumb navigation for certain routes

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 });

Customization

Custom Breadcrumb template (add icons, change text, add i18n ability, etc)

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

Change text case

  {
    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>

Add icons in front of label

  • 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>

Internationalization - i18n

  • 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>

Custom separator

  • 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.

string as separator

<my-xng separator=">"></my-xng>

icon or component as separator

<my-xng [separator]="iconTemplate"></my-xng>

<ng-template #iconTemplate>
  <mat-icon>arrow_right</mat-icon>
</ng-template>

Custom Breadcrumb Styles

  • <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.

    image

.my-xng-root {
  padding: 8px 16px;
  display: inline-block;
  border-radius: 4px;
  background-color: #e7f1f1;
}

.my-xng-separator {
  padding: 0 4px;
}

Disable Auto Generation of breadcrumb labels

  • 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>

Intercept the routing via breadcrumb navigation - routeInterceptor

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,
});

API

App Route Config -> data -> breadcrumb

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

my-xng component

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

BreadcrumbService.set(pathOrAlias, breadcrumb)

argument Description Type
pathOrAlias full route path or alias prefixed with '@' string
breadcrumb breadcrumb data to update for a route `string

Where to define breadcrumbs, if Routes path have same Route specificity

  • 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.

With Component and its Children

  // 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' }
    ]
  }

With Module and its Children

  // 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' }}

Accessibility

  • A <nav> with aria-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.

Local Development

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 at http://localhost:4200/ automatically.

Build

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.

Publish to npm

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

Tests

=======

  • SSR: Supports server side rendering with nguniversal

b31cb894c3840682f98af3c97d07b45524e205ff

Contributors ✨

Thanks goes to these wonderful people (emoji key):

<<<<<<< HEAD

=======


Uday Vunnam

💻 📖 🚧

anthonythiry

💻

dedrazer

💻

Danny Feliz

📖
>>>>>>> b31cb894c3840682f98af3c97d07b45524e205ff

<<<<<<< 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

About

A lightweight, configurable and reactive breadcrumbs for Angular 2+

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 69.7%
  • HTML 16.9%
  • JavaScript 6.7%
  • CSS 5.8%
  • Other 0.9%