Skip to Content
Technical Articles

UI5 – Navigate with Nested Components

*Note Sample code is at https://github.com/Yelcho/UI5-Nested-Comp-Routing/

A couple of months ago I wrote this blog describing how to use Component-based Routing in your UI5 applications.

In it I mentioned how I had come across an issue with routing between nested components and the way I worked around it. Since then the issue I raised has been resolved in the 1.72 version of the SAPUI5 libraries. In this blog I describe how the latest library can now support routing to nested components.

With nested components we get a situation like this..

This diagram represents 3 different components. Each component has its’ own view(s) and router for navigating between those views.

The main components’ router is configured to navigate to the respective child components. These child components may have many different routes and some may use routing parameters for passing context information. So it is important that the main router can pass these parameters to the child routers.

As of v1.72 of the UI5 libraries the sap.ui.core.routing.Router class “navTo” method has been enhanced to support passing route information to the router of a nested component. You can find the documentation here.

In my original blog I described how to configure the router to support nested components. You might find it worthwhile to review those details to get an understanding of how component-based routing works.

The relevant parts of the main component manifest.json file for defining the “products” child component look like this…

{
  ...
	"sap.ui5": {
    ...
		"componentUsages": {
      ...
			"productsComponent": {
				"name": "yelcho.reuse.products",
				"settings": {},
				"componentData": {},
				"lazy": true
			}
		},
    ...
		"routing": {
      ...
			"routes": [
        ...
				{
					"name": "products",
					"pattern": "products",
					"target": {
						"name": "products",
						"prefix": "p"
					}
				}
			],
			"targets": {
        ...
				"products": {
					"type": "Component",
					"usage": "productsComponent"
				},
        ...
			}
		}
	}
}

Note how…

  • components are declared in the sap.ui5.componentUsages section
  • routes have a prefix property assigned
  • targets are defined with type “Component” and usage referring to a component from the sap.ui5.componentUsages section.

The “products” components’ routing configuration contains a route for the detail page that uses the “id” parameter to pass across the primary key of the relevant product.

"routes": [
  ...
  {
    "name": "detail",
    "pattern": "detail/{id}",
    "target": "detail"
  },
  ...
],

With the new enhanced sap.ui.core.routing.Router class I can now, for example, use the main router to navigate to the products component and pass parameters that tell it to open the “detail” route using the product id of 4.

this.getOwnerComponent()
  .getRouter()
  .navTo(
    "products",
    {},
    {
      products: {
        route: "detail",
        parameters: {
          id: "4"
        }
      }
    }
  )

However there remains one outstanding problem. If I want to navigate from one child component to another child component the source component needs to be able to call the “navTo” method of the main components’ router rather than its’ own router. So how can I find the main router from within a subcomponent?

I decided to do it by recursively walking up the ancestor tree of the subcomponent until I found the main component. To be able to accurately identify the main component I pass its’ name to the subcomponent by defining it as a parameter in the “componentData” section of the component definition on the manifest.json file of the main component.

"productsComponent": {
  "name": "yelcho.reuse.products",
  "settings": {},
  "componentData": {
    "parentComponentName": "yelcho.mydemo.nestcomproute.Component"
  },
  "lazy": true
}

Then I can find the parent component from the child component like this …

getMainComponent: function() {
  let oElement = this.oContainer
  while (oElement && !this._mainComponent) {
    try {
      oElement = oElement.getParent()
      if (
        oElement.getMetadata().getName() ===
        this.oComponentData.parentComponentName
      ) {
        this._mainComponent = oElement
      }
    } catch {}
  }
  return this._mainComponent ? this._mainComponent : this
},

… and find the main component router like this …

getMainRouter: function() {
  return this.getMainComponent().getRouter()
}

So now the event handler for navigating from one subcomponent to another would look like this…

onPressProduct: function(oEvent) {
  this.getOwnerComponent()
    .getMainRouter()
    .navTo(
      "products",
      {},
      {
        products: {
          route: "detail",
          parameters: {
            id: oEvent
              .getSource()
              .getBindingContext()
              .getProperty("ProductID")
          }
        }
      }
    )
}

Jiawei Cao from SAP, who was responsible for changing the sap.ui.core.routing.Router class, came up with another way for the subcomponents to hook into the main router.

He uses the ‘created’ event on the target cache of the main router to build event handlers for each of the subcomponent routing options. Then, rather than call the main router directly he fires the appropriate event to trigger the handler that calls the ‘navTo’ method of the main router and provides the route information the subcomponent router requires.

So his event handlers look like this …

onPressCategory: function(oEvent) {
  this.getOwnerComponent().fireEvent("toProduct", {
    id: oEvent
      .getSource()
      .getBindingContext()
      .getProperty("SupplierID")
  })
},

His full sample can be found in the UI5 SDK at https://github.com/SAP/openui5/tree/master/src/sap.ui.core/test/sap/ui/core/demokit/sample/RoutingNestedComponent

Until it is properly linked into the SDK like the other samples the best way to find it is probably to clone the https://github.com/SAP/openui5 repository to your local system and look at it there.

Finally, I took my samples from the previous blog and updated them to use this new routing concept. You can find the updated code at https://github.com/Yelcho/UI5-Nested-Comp-Routing and execute the samples at https://yelcho.github.io/UI5-Nested-Comp-Routing/.

Enjoy!

2 Comments
You must be Logged on to comment or reply to a post.
  • Excellent news.

    One thing is still unclear to me though. Do we still have to define the parentComponent name in the route of the child component? Because that is still a design-nono from my side.

    Jiawei Cao‘s solution to trigger the parent navigation from a child component is an excellent solution. By the book, as it should be. Communication from child to parent flows via events, or property bindings. Never via method calls, since the child doesn’t know who its parent might be.

    Looks like I may have to update my Component-template.

    https://gitlab.com/fiddlebe/ui5/templates/component/blob/master/webapp/controller/BaseController.js#L145

    • Hi Tom,

      defining the parentComponent name is merely to support the method I used for finding the parentComponent from the childComponent.

      You are right that Jason’s solution is worth a closer look – I just didn’t have time to put more details into this blog as it was already a few weeks later than I planned. If I get the chance over the Christmas break I will expand on those details a bit.

      Cheers

      Graham Robbo