Skip to content
Snippets Groups Projects
shared-breadcrumb.presentational.ts 4.83 KiB
Newer Older
import {
  ChangeDetectionStrategy,
  Component,
  OnInit,
  Output,
} from "@angular/core";
import {
  ActivatedRoute,
  NavigationEnd,
  Router,
} from "@angular/router";
import {SharedAbstractPresentational} from "@app/shared/components/presentationals/shared-abstract/shared-abstract.presentational";
import {Breadcrumb} from "@app/shared/models/breadcrumb.model";
import {TranslateService} from "@ngx-translate/core";
import {Store} from "@ngxs/store";
import {DlcmData} from "@shared/models/dlcm-route.model";
import {
  BehaviorSubject,
  Observable,
} from "rxjs";
import {distinctUntilChanged} from "rxjs/internal/operators/distinctUntilChanged";
import {
  filter,
  map,
} from "rxjs/operators";
import {
  isUndefined,
  ObservableUtil,
  TRANSLATE,
} from "solidify-frontend";
  selector: "dlcm-shared-breadcrumb",
  templateUrl: "./shared-breadcrumb.presentational.html",
  styleUrls: ["./shared-breadcrumb.presentational.scss"],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SharedBreadcrumbPresentational extends SharedAbstractPresentational implements OnInit {
  breadcrumbsObs: Observable<Breadcrumb[]>;
  private readonly _navigateBS: BehaviorSubject<string | undefined> = new BehaviorSubject<string | undefined>(undefined);

  @Output("navigateChange")
  readonly navigateObs: Observable<string | undefined> = ObservableUtil.asObservable(this._navigateBS);
  private readonly _BREADCRUMB_KEY: string = "breadcrumb";
  private readonly _BREADCRUMB_TRANSLATE_HOME: string = TRANSLATE("breadcrumb.home");

  constructor(private translate: TranslateService,
              private router: Router,
              private activatedRoute: ActivatedRoute) {
    super();
  }

Florent Poittevin's avatar
Florent Poittevin committed
  ngOnInit(): void {
    super.ngOnInit();
    this.breadcrumbsObs = this.router.events
      .pipe(
        filter(event => event instanceof NavigationEnd),
        distinctUntilChanged(),
        map(event => this.buildBreadCrumb(this.activatedRoute.root)),
      );
  }

  buildBreadCrumb(route: ActivatedRoute,
                  url: string = "",
                  breadcrumbs: Breadcrumb[] = []): Breadcrumb[] {
    const label: string = this.getLabel(route);
    const labelObs = this.getBreadcrumbMemoizedSelector(route);
    const path = this.getPath(route);
    url = `${url}${path}/`;

    if (!isUndefined(label) || !isUndefined(labelObs)) {
      const breadcrumbElement: Breadcrumb = {
        label,
        url: url,
        noLink: this.getNoLink(route),
      } as Breadcrumb;
      breadcrumbs = [...breadcrumbs, breadcrumbElement];
    }
    if (route.firstChild) {
      return this.buildBreadCrumb(route.firstChild, url, breadcrumbs);
    return breadcrumbs;
  private getLabel(route: ActivatedRoute): string | undefined {
    if (route.routeConfig) {
      const routeConfig = route.routeConfig;
      if (isNullOrUndefined(routeConfig.data) || isNullOrUndefined(routeConfig.data[this._BREADCRUMB_KEY])) {
        // console.warn(`Please define the data '${this._BREADCRUMB_KEY}', for the following route ${route.toString()}`);
        return undefined;
      return route.routeConfig.data[this._BREADCRUMB_KEY];
    return this._BREADCRUMB_TRANSLATE_HOME;
  private getBreadcrumbMemoizedSelector(route: ActivatedRoute): Observable<string> | undefined {
    if (isNullOrUndefined(route.routeConfig) || isNullOrUndefined(route.routeConfig.data)) {
Florent Poittevin's avatar
Florent Poittevin committed
    }
    const breadcrumbMemoizedSelector = (route.routeConfig.data as DlcmData).breadcrumbMemoizedSelector;
    if (!isNullOrUndefined(breadcrumbMemoizedSelector)) {
      return this.store.select(breadcrumbMemoizedSelector);
    }
    return undefined;
Florent Poittevin's avatar
Florent Poittevin committed
  }

  private getNoLink(route: ActivatedRoute): boolean {
    if (isNullOrUndefined(route.routeConfig) || isNullOrUndefined(route.routeConfig.data)) {
      return false;
    }
    const noBreadcrumbLink = (route.routeConfig.data as DlcmData).noBreadcrumbLink;
    if (isTrue(noBreadcrumbLink)) {
      return true;
    }
    return false;
  }

Florent Poittevin's avatar
Florent Poittevin committed
  private getPath(route: ActivatedRoute): string {
    if (route.routeConfig) {
      let path = route.routeConfig.path;
      path = this.insertParametersInPath(route, path);
      return path;
    }
    return StringUtil.stringEmpty;
Florent Poittevin's avatar
Florent Poittevin committed
  private insertParametersInPath(route: ActivatedRoute, path: string): string {
    const params = route.snapshot.params;
    // tslint:disable-next-line:forin
    for (const key in params) {
      path = path.replace(`:${key}`, params[key]);
    }
    return path;
  }

  navigate(breadcrumb: Breadcrumb): void {
    if (this.haveNoLink(breadcrumb)) {
    this._navigateBS.next(breadcrumb.url);
  haveNoLink(breadcrumb: Breadcrumb): boolean {
    return this.router.url + "/" === breadcrumb.url || breadcrumb.noLink;