Skip to Content
Technical Articles

UI5 – Nested routing with reusable components

intro

When building large and complex UI5 apps, you will probably at some point start creating reusable components which you embed in a container app. The advantage of such a reusable component is that you can repeatedly use it in several apps. For most of the scenarios, the standard UI5 doco will suffice, until you need to have routing in a subcomponent, and deeplinks that you can share with colleagues.

So imagine you have a parent component with 2 routes, that each show their respective subcomponent:

  • project
  • reservation

And your reservation component has 2 routes:

  • list
  • detail

Scenario sounds simple enough, right?

The official way

The official UI5 doco requires you to specify the parent route in your subcomponent. That is for me a big nono, since the child component must be parent agnostic. Otherwise, it’s not really a reusable component, since it will only work in those parent components that are predefined.

Secondly, I tried that approach, and for some reason, if you simply copy paste the url to another session, the parent routing isn’t applied, since the router of the parent can’t match the full route (“reservation/detail/50”) to any of its own patterns.

In other words: the standard way just doesn’t cut it.

Wildcards

So I decided to take a different approach and play with wildcards.

I defined my parent routes as following:

{
  "pattern":"project",
  "name":"project",
  "target":["project"]
},
{
  "pattern":"reservation/&:child*:",
  "name":"reservation",
  "target":["reservation"]
}

*Notice the use of the “:child*:” parameter. It’s an optional wildcard that catches anything trailing the URL. This will ensure that “reservation/detail/50” is also considered as a valid reservation route by the parent router.

**you’ll also notice how I added ampersands to separate the parent part and the child part. This helps the router to distinguish the patterns if your child and parent component happen to have the same parameter names, or URL parts.

the childroutes are defined as following:

{
  "pattern": ":parent*:&/list",
  "name": "List",
  "target": ["List"]
},{
  "pattern": ":parent*:&/Detail/{ResId}",
  "name": "Detail",
  "target": ["Detail"]
},{
  "pattern": ":parent*:",
  "name": "home",
  "target": ["List"]
}

*Notice how this time, there is a leading wildcard for parent information. The last route contains only the parent wildcard, and is meant to show the default target (List). That way the URIs “reservation/” and “reservation/list” will both show the reservation list.

So this works perfect to recognize the URLs and show the right targets.

There is however still a catch. When you navigate internally in the reservation subcomponent, you may have a navto(“detail”,{ResId:50}) statement. This would replace the complete URL hash to “/detail/50”, which is not recognized by the parent component. So if you share that URL, it wouldn’t work, since the result in the app would be the project-list. In other words, we need to have a solution to automatically inject the parent, and child route-parts in the navigation parameters.

Fortunately, I inherit all my controllers from my own BaseController, in which I have some convenience methods. (like: getRouter, getModel etc…). So I just added a couple more convenience methods:

First of all, I defined an onRouteMatched handler that simply takes the navigation-parameters and keeps them in a simple variable. You can consider other options:

  • keep it in a settings-model
  • move everything to the component, and define a nice property on the component

To automatically consider the parent and child properties during navigation, I added another convenience method (navTo). That way, in your controller, you can just call

this.navTo("Detail", {ResId:50});

inside the navTo method, I combine the navRoute property (containing all parent and child parameters and anything else) and your specific parameters into a new resultParams object and pass that to the router.

*yes you could use jQuery.extend here, but I refuse to depend on jQuery.

**no you can’t use Object.assign, since it doesn’t cater for deep structure. Although theoretically, you wouldn’t have deep parameters in routing. But I already hacked that as well.

advantages

  • You don’t need to define the parent route in your child component, so you have true reuse. No matter where you use this child component, the routing will work
  • having a simple navTo method means you don’t have to worry about anything beneath the bonnet.
  • You can use parent and child routing in the same pattern, meaning you can have multi-level routing (Inception!)

disadvantages

  • you need to add parent, child wildcards in your route patterns…
3 Comments
You must be Logged on to comment or reply to a post.
  • Oh snap, I built and tested this on UI5 1.60.8 and it worked fine.

    In UI5 1.65 however, apparently the ampersand separator “&” confuses the routing pattern matcher.

    I replaced it with a different separator “-” and now it’s working again…

    So consider this when you want to use this approach.

  • Hi,

    Thanks for sharing this!

    The key statement here is:  “Child components must be parent agnostic”.

    I’m still wondering why this is not taken into consideration in the various documentations that SAP and OpenUI5 provide.

    Thanks again.
    Claude