Recursive routes in Angular
Tags: angular, typescript, spa, javascript
Published: 2019-11-24 10:49:40

### 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:
```typescript
@NgModule({
    imports: [
        RouterModule.forRoot([
            { path: '', component: BranchComponent }
        ])
    ],
    exports: [RouterModule]
})
export class BranchRoutingModule { }
```
###### After:
```typescript
@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:
```typescript
{ 
    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. 
```typescript
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.
```typescript
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. 😉😛