peterbsmyth / ngx-breadcrumbs

Angular 4+ routing breadcrumbs
MIT License
60 stars 43 forks source link

Breadcrumbs not displaying with resolver #24

Open tomrainedotcom opened 5 years ago

tomrainedotcom commented 5 years ago

Can anyone help me out here? I have a custom Breadcrumb resolver to get names of events and there units from dynamic data, logging shows the array of breadcrumbs is compiled correctly but I only get a "1." displayed where the breadcrumb is supposed to be.

Is the following the correct way to return Observable<IBreadcrumb[]>?

I am using Angular 6 and have used the git repo and built out the Angular 6 converted version.

BreadcrumbResolver

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { IBreadcrumb, McBreadcrumbsResolver } from 'ngx-breadcrumbs';
import { EventsService } from './events.service';
import { EventModel } from '../Models/event.model';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class BreadcrumbResolver extends McBreadcrumbsResolver {
  private event: EventModel;
  constructor( private router: Router, private eventsService: EventsService) { super(); }

  resolve (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<IBreadcrumb[]> {
    const breadCrumbs: Array<IBreadcrumb> = [];
    return new Observable((observer) => {
      this.eventsService.getEvent(route.params.id || route.parent.params.id).subscribe( (event) => {
        if (route.params.unitId || route.parent.params.unitId) {
          breadCrumbs.push({
            text: event.name,
            path: this.router.createUrlTree(['events', event._id]).toString()
          });
          let unitName = '';
          event.courses.forEach( (course) => {
            if (course !== null) {
              const foundUnit = course.units.find((unit) => {
                return unit.id === (route.params.unitId || route.parent.params.unitId);
              });
              if (foundUnit) {
                unitName = foundUnit.name;
                breadCrumbs.push({
                  text: unitName,
                  path: this.router.createUrlTree(['events', event._id]).toString()
                });
              }
            }
          });
          observer.next(breadCrumbs);
        } else {
          // no unit id available so we just need to event breadcrumb
          breadCrumbs.push({ text: event.name, path: this.router.createUrlTree(['events', event._id]).toString() });
          observer.next(breadCrumbs);
        }
      });
      return observer.complete();
    });
  }
}

Routing Module

const eventsRoutes: Routes = [
  {
    path: '',
    component: EventsComponent,
    data: {title: 'Events', breadcrumbs: 'Events'},
    canActivate: [AuthGuardService]
  },
  {
    path: ':id',
    component: EventComponent,
    data: {title: 'Event'},
    children: [
      {
        path: 'overview',
        component: OverviewComponent,
        data: {title: 'Event Overview', breadcrumbs: BreadcrumbResolver}
      },
      {
        path: 'participants',
        component: ParticipantsComponent,
        data: {title: 'Event Participants', breadcrumbs: BreadcrumbResolver}
      },
      {
        path: 'assessments',
        component: AssessmentsComponent,
        data: {title: 'Event Assessments', breadcrumbs: BreadcrumbResolver}
      }
    ]
  },
  {
    path: ':id/assessments/:unitId',
    component: LearningAssessmentComponent,
    data: {title: 'Learning Assessment', breadcrumbs: BreadcrumbResolver},
  },
];

Logged breadcrumbs image

How it looks in the DOM image

ericzon commented 5 years ago

I have exactly the same problem... I imagine it's related how it's handled this._resolveCrumbs(route) in mc-breadcrumbs.service but I'm not very familiar with this.

dang312 commented 5 years ago

Better approach here is to use resolver to retrieve data and store in route data. Then use the route information to build breadcrums like normal ( because now in route data you have the unitName ) . UnitResolver

@Injectable()
export class UnitResolver implements Resolve<Observable<boolean>> {
    constructor(private eventsService: EventsService) { }

    public resolve(route: ActivatedRouteSnapshot): Observable<string> {
        return new Observable<string>((observer) => {
            // Your old code , just put it back here
            this.eventsService.getEvent(route.params.id || route.parent.params.id).subscribe((event) => {
                event.courses.forEach((course) => {
                    if (course !== null) {
                        let unitName = '';
                        const foundUnit = course.units.find((unit) => {
                            return unit.id === (route.params.unitId || route.parent.params.unitId);
                        });
                        if (foundUnit) {
                            unitName = foundUnit.name;
                            observer.next(unitname);
                            observer.complete();
                        }
                        // TODO: Handle case if not found the unit here ?
                    }
                });
            });
        });
    }
}

some routing example :

{
        path: 'overview',
        component: OverviewComponent,
        data: {title: 'Event Overview', breadcrumbs: BreadcrumbResolver},
        resolve : {
           unitName: UnitResolver ,
       }
}

Usage in BreadcrumbsResolver

const unitName= routeSnapshot.data.unitName;
breadCrumbs.push({
                  text: unitName,
                  path: this.router.createUrlTree(['events', event._id]).toString()
});