Leveraging embedded routing in multiple components to structure big UI5 applications

This blog post aims to talk about a technique that, while possible to implement, is not really documented (as far as I know) as such across the extensive notes and documentation that UI5 offers. Specifically, we’re talking about how we can use embedded routing (that is, multiple routers working in tandem to allow multiple components, each with their own routing, to be in a single UI5 app).

We found this technique especially useful in large-scale applications with upwards of 50-60 view-controller pairs, where it can be really useful to modularize and isolate the different parts of the app into their own isolated silos. A typical use case for these kinds of apps is Apache Cordova, where big hybrid mobile applications can have upwards of a hundred views. In these cases, modularizing into multiple components to isolate logic and UI, as well as to allow future development and code scaling without having to save dozens of XML and JS files into a single folder can be essential.

We’ll illustrate this technique by using a sample application (the GitHub link is available at the end of the article). First we’ll show a diagram showing the UI structure:

This basic diagram gives us an idea of what we want to accomplish with the sample app. Namely:

  • We want a Root Component which contains the navigation list (in the master) and the multiple views which contain the Component Containers for our subcomponents (in the detail).
  • We want two Sub Components, each with their own routing, which have compatible routes with the root router.

The basic routing scheme we need to accomplish this is illustrated here:

Root Router:

“routes”: [
“pattern”: “component1/:viewPattern:”,
“name”: “sub1ComponentView”,
“target”: [“masterView”, “component1View”]
“pattern”: “component2/:viewPattern:”,
“name”: “sub2ComponentView”,
“target”: [“masterView”, “component2View”]
“targets”: {
“masterView”: {
“viewName”: “Master”,
“viewId”: “master”,
“title”: “Navigation List”,
“controlAggregation”: “masterPages”
“component1View”: {
“viewName”: “Component1View”,
“viewId”: “component1View”,
“controlAggregation”: “detailPages”
“component2View”: {
“viewName”: “Component2View”,
“viewId”: “component2View”,
“controlAggregation”: “detailPages”

SubComponent Router:

“routes”: [
“pattern”: “component1/view1”,
“name”: “sub1view1”,
“target”: “targetSub1View1”
“pattern”: “component1/view2”,
“name”: “sub1view2”,
“target”: “targetSub1View2”
“targets”: {
“targetSub1View1”: {
“viewName”: “Sub1View1”,
“viewLevel”: 1,
“viewId”: “idSub1View1”,
“controlAggregation”: “pages”
“targetSub1View2”: {
“viewName”: “Sub1View2”,
“viewLevel”: 2,
“viewId”: “idSub1View2”,
“controlAggregation”: “pages”

As can be surmised by the routing pattern, the idea here is to make the Root router and the Sub routers routes compatible with each other. We accomplish this by ending all patterns of the Root router with a “:viewPattern:” optional routing parameter and implementing all patterns of the Sub routers as subroutes of the component route in the Root router. Breaking this pattern (for example, having a hypothetical view in a subcomponent with a pattern “view3”), would mean that the Sub router would route correctly, but because the Root router does not have any pattern with that name, it would show no component container and therefore the detail would show up empty).

As for the folder structure, a possible one would be this:

We’re using the UI5 basic template found here:

An argument could be made in favour of storing the subcomponents in a folder inside the RootComponent, to reflect the UI structure. Speaking for myself, I like the inmediacy of having all components available in a single click by using a flat structure instead of a nested one, but your mileage may vary. Both approaches are perfectly possible leveraging the flexibility UI5 offers with namespaces in the different modules that comprise the app.

The RootComponent should have the following structure:

That is, one view for the Root SplitApp control, one for the master List, plus one for each component container, for all components that we wish to expose.

The component container views have been implemented like this:


<mvc:View busyIndicatorDelay="0"
		<core:ComponentContainer id="sub1CmpCtr" height="100%" />


  ["sap/ui/core/mvc/Controller", "sap/ui/core/Component", "../model/formatter"],
  function(Controller, Component, formatter) {
    "use strict";

    return Controller.extend(
        formatter: formatter,

        onInit: function() {
          if (!Component.get("sub1Component")) {
              name: "",
              id: "sub1Component"
              function(Component) {

Not much to note here, the view simply contains a ComponentContainer control that only gets instantiated and filled with a Component when the onInit method of the controller gets triggered. This only happens the first time we navigate to a new component, thus allowing components to be lazy loaded (which should help performance if the user only navigates to some specific parts of the app while leaving others alone in a session).

As for the subcomponents, they are perfectly normal full screen (instead of master detail) UI5 components, with two caveats:

  • As discussed earlier, all routes should be prefixed with the component route
  • The App.view.xml file should not have a sap.m.Shell inside since that UI control is already emitted by the Root Controller

With this, we have almost every piece of the puzzle figured out, but we still need to know:

  • How to trigger a navigation from the root component into the subcomponents (necessary for the master list)
  • How to trigger a navigation from one subcomponent view into a different subcomponent view

Let’s answer the first question.

Triggering a navigation from a controller owned by the RootComponent into a specific view is as simple as:

.navTo(“sub1ComponentView”, {
viewPattern: “view1”

The reason this works is that we’re telling the Root router to write the hash “sub1ComponentView/view1”. When it does that bot the Root router and the sub component router capture that event, thus the root router navigates to the correct component container and the sub component router navigates to the correct view, provided the above constraints on the routing structure of the app are met.

Knowing this, answering the second question is trivial.

From the controller of the view of the subcomponent we fire an event using the EventBus attached to the core (not the one attached to the subcomponent, since obviously that one won’t be able to emit events outside its domain).

sap.ui.getCore().getEventBus().publish(“nav”, “sub2component:view1”);

And then, from the RootComponent, we should have a dedicated method with the following code:

sap.ui.getCore().getEventBus().subscribe(“nav”, “sub2component:view1”, function() {
.navTo(“sub2ComponentView”, {
viewPattern: “view1”
}, this);

Note that the reason we’re doing this in RootComponent instead of Sub2Component is that we’re not guaranteed at any point that Sub2Component will be instantiated, since we’re lazy loading all our components.

With this, we have all the elements we need, and this is the result of our hard work:

Which may not be the prettiest UI5 application you’ve seen, but it’s a proof of concept so oh well.

More Info: SAP Certifications

Leave a Reply

Your email address will not be published.