1.1. Component Breadcrumbs - quan1997ap/angular-app-note GitHub Wiki

USE

  1. Type
<vcs-breadcrumbs></vcs-breadcrumbs>
<vcs-breadcrumbs [type]="'long'"></vcs-breadcrumbs>
<vcs-breadcrumbs [type]="'long-wrap'"></vcs-breadcrumbs>
<vcs-breadcrumbs [type]="'truncation'"></vcs-breadcrumbs>
  1. Modules
import { BreadcrumbsModule } from 'vcs-material';

const routes: Routes = [

  // breadcrumbs with static lable
  {
    path: 'breadcrumbs',
    component: BreadcrumbsComponent,
    data: {
      breadcrumb: [
        {
          label: 'Home',
          url: '/',
        },
        {
          label: 'Breadcrumbs',
          url: '/component/breadcrumbs',
          icon: 'vcs-layout-dashboard'
        },
        {
          label: 'Detail',
        }
      ]
    }
  },
  // breadcrumbs with dynamic lable ( get data from params )
  {
    path: ':id/:name/detail',
    component: DatasourceDetailComponent,
    data: {
      breadcrumb: [
        {
          label: 'Home',
          url: '/'
        },
        {
          label: 'Datasources',
          url: '/datasource-management'
        },
        {
          label: '//:name//',
        }
      ]
    }
  }
]


@NgModule({
  imports: [
    BreadcrumbsModule,
    RouterModule.forChild(routes)
  ]
})

HTML:

<ng-container *ngIf="breadcrumbConfigs && breadcrumbConfigs.length">

    <ul class="breadcrumb" *ngIf="(type !== 'truncation') || ( type == 'truncation' && breadcrumbConfigs.length <= 2)" [ngClass]="{
        'long-wrap': type == 'long-wrap',
        'long': type == 'long'
      }">
        <li *ngFor="let breadcrumb of breadcrumbConfigs; let i = index;">
            <ng-container>
                <mat-icon *ngIf="breadcrumb.icon" svgIcon="{{ breadcrumb.icon }}" color="primary" class="small breadcrumb-icon"></mat-icon>
                <a [routerLink]="breadcrumb.url" *ngIf="breadcrumb.url" routerLinkActive="router-link-active">
                  {{ breadcrumb.label }}
                </a>
                <span *ngIf="!breadcrumb.url" routerLinkActive="router-link-active">
                  {{ breadcrumb.label }}
                </span>
                <span class="separate-character">
                  {{separateCharacter}}
                </span>
            </ng-container>
        </li>
    </ul>

    <ul class="breadcrumb truncation" *ngIf="type === 'truncation' && breadcrumbConfigs.length > 2 ">
        <li>
            <mat-icon *ngIf="breadcrumbConfigs[0].icon" svgIcon="{{ breadcrumbConfigs[0].icon }}" color="primary" class="small breadcrumb-icon"></mat-icon>
            <a [routerLink]="breadcrumbConfigs[0].url" *ngIf="breadcrumbConfigs[0].url" routerLinkActive="router-link-active">
                {{ breadcrumbConfigs[0].label }}
              </a>
            <span *ngIf="!breadcrumbConfigs[0].url" routerLinkActive="router-link-active">
                {{ breadcrumbConfigs[0].label }}
              </span>
            <span class="separate-character">
                  {{separateCharacter}}
              </span>
        </li>
        <li>
            <span>...</span>
            <span class="separate-character">
              {{separateCharacter}}
          </span>
        </li>
        <li>
            <mat-icon *ngIf="breadcrumbConfigs[breadcrumbConfigs.length - 1].icon" svgIcon="{{ breadcrumbConfigs[breadcrumbConfigs.length - 1].icon }}" color="primary" class="small breadcrumb-icon"></mat-icon>
            <a [routerLink]="breadcrumbConfigs[breadcrumbConfigs.length - 1].url" *ngIf="breadcrumbConfigs[breadcrumbConfigs.length - 1].url" routerLinkActive="router-link-active">
              {{ breadcrumbConfigs[breadcrumbConfigs.length - 1].label }}
            </a>
            <span *ngIf="!breadcrumbConfigs[breadcrumbConfigs.length - 1].url" routerLinkActive="router-link-active">
              {{ breadcrumbConfigs[breadcrumbConfigs.length - 1].label }}
            </span>
            <span class="separate-character">
                {{separateCharacter}}
            </span>
        </li>
    </ul>

</ng-container>

SCSS:

$breadcrumb-color: #848792;
$breadcrumb-active-color: #1a77c7 !important;
$font-family: 'FVHCircularXX-Medium';
$font-size: 14px;
$height-item: 28px; // = 2 * $font-size
.d-none {
    display: none !important;
}

@mixin baseTextStyle {
    font-size: $font-size;
    font-family: $font-family;
    color: $breadcrumb-color;
    white-space: nowrap;
}

.breadcrumb {
    background: none;
    width: fit-content;
    font-size: $font-size;
    display: block;
    margin: 0;
    display: flex;
    padding-left: 0;
    width: 100%;
    flex-wrap: wrap;
    &.long {
        overflow: auto;
        flex-wrap: nowrap;
    }
    &.long-wrap {
        overflow: auto;
        flex-wrap: wrap;
    }
    &.truncation {
        overflow: auto;
        flex-wrap: nowrap;
    }
    a {
        @include baseTextStyle;
        &:hover {
            color: $breadcrumb-active-color !important;
            text-decoration: none;
        }
    }
    span {
        @include baseTextStyle;
    }
    li {
        list-style: none;
        float: left;
        margin: 0 4px;
        display: flex;
        justify-content: center;
        align-items: center;
        line-height: $height-item;
        height: $height-item;
        .breadcrumb-icon {
            font-size: 16px;
            margin-right: 4px;
            transform: scale(0.8);
        }
        .separate-character {
            color: $breadcrumb-color;
            font-size: 16px;
            margin-left: 8px;
        }
        .toggle-collapse {
            cursor: pointer;
        }
        &:last-child {
            &::after {
                content: "";
            }
            .separate-character {
                display: none;
            }
        }
    }
}

TS:

// https://dev.to/zhiyueyi/create-a-simple-breadcrumb-in-angular-ag5
import { ChangeDetectorRef, Input } from '@angular/core';
import { Component, OnInit } from "@angular/core";
import {
  ActivatedRoute,
  Router,
  NavigationEnd,
} from "@angular/router";
import { filter } from "rxjs/operators";

@Component({
  selector: 'vcs-breadcrumbs',
  templateUrl: './breadcrumbs.component.html',
  styleUrls: ['./breadcrumbs.component.scss']
})
export class BreadcrumbsComponent implements OnInit {
  @Input() type = 'long-wrap'; // 'long', 'long-wrap', 'truncation';
  @Input() separateCharacter = '/'; // '/', ',', '.';

  collapsed = true;
  breadcrumbConfigs: Breadcrumb[] = [];

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute,
    private cd: ChangeDetectorRef
  ) {
  }

  ngOnInit() {
    this.breadcrumbConfigs = this.buildBreadCrumb(this.activatedRoute.root);
    this.cd.detectChanges();
    this.router.events
      .pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
        this.breadcrumbConfigs = this.buildBreadCrumb(this.activatedRoute.root);
        window.scrollTo(0, 0);
        this.cd.detectChanges();
      });
  }


  buildBreadCrumb(route: ActivatedRoute, url: string = '', breadcrumbs: Breadcrumb[] = []): Breadcrumb[] {

    let sliceChar = '//';
    //If no routeConfig is avalailable we are on the root path
    let breadcrumbConfigs = route.routeConfig && route.routeConfig.data ? route.routeConfig.data.breadcrumb : '';
    let path = route.routeConfig && route.routeConfig.data ? route.routeConfig.path : '';

    // If the route is dynamic route such as ':id', remove it and exchange with data from params
    if (breadcrumbConfigs && breadcrumbConfigs.length) {
      breadcrumbConfigs = breadcrumbConfigs.map((breadCrumb: Breadcrumb) => {
        const breadCrumbLabelSplits = breadCrumb.label.split(sliceChar);
        // console.log(breadCrumbLabelSplits)
        const breadCrumbWithLabelMappingVal: string[] = breadCrumbLabelSplits.map(label => {
          if (label.charAt(0) === ':') {
            const labelMappingParam = route.snapshot.params[label.slice(1, label.length)];
            label = labelMappingParam ? labelMappingParam : label;
          }
          return label;
        });
        return {
          label: breadCrumbWithLabelMappingVal.join(''),
          url: breadCrumb.url,
          icon: breadCrumb.icon,
        };
      });
    }

    //In the routeConfig the complete path is not available,
    //so we rebuild it each time
    const nextUrl = path ? `${url}/${path}` : url;

    // Only adding route with non-empty label
    const newBreadcrumbs = breadcrumbConfigs ? breadcrumbs.concat(breadcrumbConfigs) : breadcrumbs;
    if (route.firstChild) {
      //If we are not on our current path yet,
      //there will be more children to look after, to build our breadcumb
      return this.buildBreadCrumb(route.firstChild, nextUrl, newBreadcrumbs);
    }
    if (newBreadcrumbs) {
      return newBreadcrumbs;
    } else {
      return [];
    }
  }


  toggleCollapseBreadcrumb(){
    this.collapsed = !this.collapsed;
  }
}

export interface Breadcrumb {
  label: string;
  url: string;
  icon: string;
}


MODULE

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BreadcrumbsComponent } from "./breadcrumbs.component";
import {MatIconModule} from '@angular/material/icon';
import { RouterModule } from '@angular/router';


@NgModule({
  declarations: [
    BreadcrumbsComponent
  ],
  imports: [
    CommonModule,
    RouterModule,
    MatIconModule
  ],
  exports: [
    BreadcrumbsComponent
  ]
})
export class BreadcrumbsModule { }


⚠️ **GitHub.com Fallback** ⚠️