Skip to content
This repository has been archived by the owner on Nov 9, 2021. It is now read-only.

Migration from ember-crumbly due to no longer being maintained #149

Open
cah-brian-gantzler opened this issue Jun 10, 2021 · 0 comments
Open

Comments

@cah-brian-gantzler
Copy link

Since this addon seems to be no longer maintained and there are issues with deprecations that need to be resolved, I did a lot of research on switching to another addon or just doing it myself. In ember 3.10, ember provided a way to do what ember crumbly was mostly doing with the breadcrumb property on the route. Given that, the other approaches did not use what ember was providing and were doing more of a toolbar approach rather that a real route hierarchy link which is what this is. When I looked at the code that needed to be done with the new ember provided hooks, there really wasnt much of an addon left besides providing a default layout for the breadcrumbs. Providing a default layout then added additional params to the components to allow you to set classes, change the tagName, etc just adding to the complexity. Since its only used in a couple places, you should just state the layout in the app and have full control. If you need it in more than one place, you can create your own component providing your own look and feel.

So, how do remove using this addon and replace it with a custom implementation. The following does one thing differently. Crumbly assumes every route in the hierarchy, if you want to skip a route you have to state breadcrumb = null. It also assumes that in lack of a breadcrumb you want it to be the route name. Since that really woundnt work for anyone using INTL (your routes names and links would be in one language), this version requires you to specify a breadcrumb on the routes you want, the opposite of assuming a breadcrumb when none exists. This would mean you may need to update your routes, but its an easy change.

First off lets start with the route/controller where you would want the breadcrumbs displayed. With ember crumby you would have in a route template

<BreadCrumbs @tagName="ol" @linkable={{true}} />

This provides a default layout, but also uses tagName which we really want to move away from. Crumbly provides a yieldable version which I am encouraging you would use all the time anyway. which might have looked something like this (taken from the docs)

{{#bread-crumbs outputStyle="bootstrap" linkable=true as |component cow|}}
  {{#bread-crumb route=cow breadCrumbs=component}}
    {{#if cow.title}}
      {{cow.title}}
    {{else}}
      {{cow.name}} ({{cow.age}}) says {{cow.says}}
    {{/if}}
  {{/bread-crumb}}
{{/bread-crumbs}}

An example of a version without crumbly would be as follows

{{#let this.routeInfos as |routeInfos|}}
  <nav>
      <ol class="breadcrumb">
        {{#each routeInfos as |routeInfo|}}
          <li>
              {{#if (has-next routeInfo routeInfos)}}
                <LinkTo
                  @route={{routeInfo.name}}
                  {{on "click" (fn this.onClickLink routeInfo)}}
                >
                  {{routeInfo.metadata.breadcrumb.title}}
                </LinkTo>
              {{else}}
                {{routeInfo.metadata.breadcrumb.title}}
              {{/if}}
          </li>
        {{/each}}
      </ol>
  </nav>
{{/let}}

(has-next) comes from ember composable helpers.
The above will make the each route a link-to with the last one being text. If you wanted the linkable=false behaviour, just remove the link-to. Now you have complete control, dont need the tagName or to pass any class params etc.

this.routeInfos is a property you need to define on the controller for the route that has the above hbs and it is as follows

 @service router;

  get routeInfos() {
    let linkListToArray = (route) => {
      return route ? [...linkListToArray(route.parent), route] : [];
    };

    let routeInfos = linkListToArray(this.router.currentRoute).filter(
      (routeInfo) => {
        return routeInfo.metadata?.breadcrumb;
      }
    );

    return routeInfos;
  }

Using the router service, this builds a list of all the routes that have breadcrumbs defined.

For each route crumbly assumed a breadcrumb and you had to specify null to skip a route. Here we must specify a breadcrumb where we want one.

example of using crumbly to define your breadcrumb (updated to a getter)

get breadCrumb()  {
    return {
        title: 'Cows'
    }
}

The way you defined a bread crumb here is exactly the same way. But you need to add the following method to the route

  buildRouteInfoMetadata() {
    return {
      breadcrumb: this.breadCrumb,
    };
  }

buildRouteInfoMetadata was introduced in 3.10 and is the route hook that is making this all happen. You could embed the definition of the breadcrumb within the return of this method if you like, but I kept them separate because it required less changes. I could just copy and paste the above method in every route I wanted.

If you refer back to the HBS above, you will see the title is referenced by routeInfo.metadata.breadcrumb.title. This means you could add any other property to the breadcrumb and then modify the HBS to react to it. In the crumbly example they show adding a property linkable. Editing the HBS could easily add this feature as well.

Thats pretty much it. I wanted to also mention this from emberMap which is a better write up for the details above, just missing any ember crumbly specifics.

Additional info: buildRouteInfoMetadata is called after the model is resolved, so you can use any model attributes in your breadcrumb and you no longer need to do it special in the afterModel which crumbly required.

More additional info: Both crumbly and this version do this, but was never called out. Since all the links are for routes above you, you do not need to specify anything like @model or @models on the link-to, they will be honored. Because query params are sticky by default, they are also honored and you do not need to specify @queryParams on your link-to either.

I have been going through every screen and removing ember-crumbly in favor or using buildRouteInfoMetadata. Hope this helps anyone else that may want to do the same.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant