Recursive routes in Angular

Recursive routes in Angular

ยท

0 min read

Prologue

You own a retail chain that has a lot of branches. You grow your business and soon realize that you won't be able to concentrate on growing business while parallelly managing all the branches yourself.

You select some prominent branches in each region (Let's call them L-0 branches) and ask that branch to manage a few branches in their region (Let's call them L-1 branches). Your chain of stores thrives under the new business model. Now all your L-0 branches have too many L-1 to manage just like you had in the beginning.

You re-organize a little more by selecting a few prominent L-1 branches and add a few L-2 branches under each of them. You keep reorganizing your chain this way up to the L-N level as the need be.

What now?

You have a portal built in Angular which has a page to show you the list of branches at example.com/branches. You find it very cumbersome to have a list of all the branches in the initial view most of which you don't manage directly. You want to have L-0 branches in the initial view and then after choosing to view the sub-branches of one of them, you want to open a list of respective L-1 branches. Similarly, you want to see a list of respective L-2 branches on choosing to view sub-branches of an L-1 branch. and so on.

What you need?

Your site so far has the following component structure.

|-app.component.ts
|-app.component.html
|-app.module.ts
|-app-routing.module.ts
|-branches
    |-branches.module.ts
    |-branches-routing.module.ts
    |-branches.component.ts
    |-branches.component.html
    |-branch
        |-branch.module.ts
        |-branch-routing.module.ts
        |-branch.component.ts
        |-branch.component.html
|-core
    |-services
        |-branch.service.ts
  • The branches component in the branches module lists all the branches.
  • The branch component in the branch module displays all the details of a particular branch.
  • /branches and /branches/<branchCode> are lazyloaded routes.

The only thing you need to do beforehand is to modify your branches API so it can accept a parentBranchCode and give you sub-branches only of that branch. Like so:

Request:
GET https://example-api.com/branches?parentBranchCode=bengaluru
Response:
[
    {
        "id": 123, 
        "branchName": "Tumakuru",
        "branchCode": "tumakuru",
        "parentBranchCode": "bengaluru"
    },
    {
        "id": 124,
        "branchName": "Mysuru",
        "branchCode": "mysuru",
        "parentBranchCode": "bengaluru"
    },
    {
        "id": 125,
        "branchName": "Mandya",
        "branchCode": "mandya",
        "parentBranchCode": "bengaluru"
    }
]

Note: In the absence of the parentBranchCode, the API should give a response containing an array of all L-0 branches.

Okay, now let's go ...

This is a breeze. You just got three things to modify in your existing code.

1. branch-routing.module.ts
Before:
@NgModule({
    imports: [
        RouterModule.forRoot([
            { path: '', component: BranchComponent }
        ])
    ],
    exports: [RouterModule]
})
export class BranchRoutingModule { }
After:
@NgModule({
    imports: [
        RouterModule.forRoot([
            { path: '', component: BranchComponent },
            { path: 'sub-branches', loadChildren: '../branches.module#BranchesModule' }
        ])
    ],
    exports: [RouterModule]
})
export class BranchRoutingModule { }

This is actually the trick. This will make the routes /branches, /branches/bengaluru/sub-branches and /branches/bengaluru/sub-branches/mysuru/sub-branches render the same component ie. BranchesComponent.

But branchCode from where?

Just to clarify, since you already have a page /branches/<branchCode>, there must be a route already in your branches-routing.module.ts like so:

{ 
    path: ':branchCode', 
    loadChildren: './branch/branch.module#BranchModule' 
}
A question you may have

In a route like /branches/bengaluru/sub-branches/mysuru/sub-branches, we have two sub-branches, there could be any number in other routes. How do we deal with this?

Short answer: You don't have to.

Long answer: If the route params of the same name appear more than once, the one appearing later will always overwrite the one preceding it. So rest assured, we are covered here. The branchCode we finally get when we subscribe to the route params will be the last one that appears in the URL (in this case, mysuru) which is what we desire.

2. branches.component.ts

You have got the branches API modified beforehand so as to accept parentBranchCode and give us back the branches managed by it (or all the L-0 branches if parentBranchCode is empty). Let' start sending this in query params.

ngOnInit() {
    const parentBranchCode = this.route.snapshot.params.branchCode;
    this.branchService.getBranches({ parentBranchCode })
    .subscribe(branches => {
        this.branches = branches;
    });
}
3. branch.service.ts

Very obviously, after the previous step, we need to pass on the query params to the API request.

getBranches(queryParams: any = {}) {
    return this.httpService.get('https://example-api.com/branches', { 
        queryParams 
    });
}
An after step

It makes sense to add a link to sub-branches in the branch component like so:

<a routerLink="sub-branches">Sub-branches</a>

Now go to /branches, you should see all your L-0 branches. Choose to view the details of that branch. Find the button you just added and click on it. You'll see a list of its sub-branches. Now choose to view any branch, find the button again, click on it. You'll get another level of branches. No end to it.

Done?

Yeah, did you expect more?

Hope you like this post. Scroll down to the comments section below and leave me your feedback or any questions you may have.

I really wish you the very best for your retail chain. ๐Ÿ˜‰๐Ÿ˜›