Skip to Content
avatar image
Former Member

Multiple Components - Routing inside a child Component

Dear all,

I want to create an application that is made of several components in order to keep things clean and separated.

From a Root Component I route to several views that contain Component Containers themselves. This navigation and the whole structure illustrated in the picture below works perfectly fine:

So I can route to patterns like

localhost:4000/

localhost:4000/first, localhost:4000/second etc. back and forth,

while these "first" and "second" views contain the Display Components (=> the "Top Level Views" in the upper picture)

The problem occurs in the routing of the Display Components. These shall have their own routing configuration, such that I can route to

localhost:4000/first/details

which specify, which view should be displayed inside the Display Component. I can't get any further here. Inside the Display Component descriptors (I use an own manifest.json for each one) I can define a router that inherits routes from the parent. Example:

manifest.json (only router part not including the targets) of first Display Component:

"routes": [
           {
             "pattern": "",
             "name": "first",
             "target": "first",
             "parent": "app.Component:first"
           },
           {
             "pattern": "details",
             "name": "details",
             "target": "details",
             "parent": "app.Component:first"
           }
         ],
"targets":{...}

And now the strange things occur: The empty pattern can be found and resolved. the correct view is displayed. But once I try to navigate to "details", it is returning my predefined (so bypassed) "notfound"-view - but the one from the Root Component!

If I change for example the empty pattern to something different that doesn't match, e.g. "test", it is returning the bypassed "notfound" view, but of the Display Component!

To make it more crazy, if I change the pattern of the "detail" to be "/" and route to it directly in my browser - it works! But only with the "/" pattern, no other pattern works.

The updated version would look like:

"routes": [
           {
             "pattern": "test",
             "name": "first",
             "target": "first",
             "parent": "app.first"
           },
           {
             "pattern": "/",
             "name": "details",
             "target": "details",
             "parent": "app.first"
           }

Has anyone experiences with such issues? I wasn't able to find comparable threads that target exactly this problem of routing in nested components. I can provide more code examples, maybe a JSBin version tomorrow, if that helps.

Thanks in advance,

Daniel

appstructure.png (35.9 kB)
Add comment
10|10000 characters needed characters exceeded

  • Get RSS Feed

1 Answer

  • Best Answer
    avatar image
    Former Member
    Oct 11, 2017 at 01:43 PM

    Well, I have found a solution myself:

    The problem is that the Root Component Router itself is called everytime you try to match a route from the Display Components. And as there is no matching route, it displays the bypassed route of the Root Component. Nevertheless, the Display View is inserted into the DOM, but kinda "overwritten" by the "notfound"-view.

    Solution: No bypassed targets at any level. Instead, use an attachBypass-Method to each router while initializing its Component. Whenever a route is found that does not match a pattern, the user is redirected to the app's landing page. This is required, since routing back to the initial Display Views (if you find a bypassed route there) makes the back-Navigation through the page header impossible => back means back to the wrong route and causes the app to stop working.

    Therefore a check of the hash-Value is required. Below you find the init-function of the Root Component:

        init: function() {
          sap.ui.core.UIComponent.prototype.init.apply(this);
          var oRouter = this.getRouter();
          oRouter.register("appRouter"); // only for Root Component Router, for accessing it from any level
          oRouter.initialize();
          oRouter.attachBypassed(function (oEvent) {
            var sHash = oEvent.getParameter("hash");
            if(sHash.indexOf("/")==-1){              // error handling only if at Top Level
              jQuery.sap.require("sap.m.MessageBox");
              sap.m.MessageBox.show(
                "You will be redirected to the Home Page.", {
                icon: sap.m.MessageBox.Icon.ERROR,
                title: "Invalid route",
                actions: [sap.m.MessageBox.Action.OK],
                onClose: function(oAction) {
                   var homeRouter = sap.ui.core.routing.Router.getRouter("appRouter");
                   homeRouter.navTo("home"); 
                 }
                });
            }
          });
        }
    

    In contrast, that's how the init-function of a Display Component is implemented:

    init: function(){
        sap.ui.core.UIComponent.prototype.init.apply(this);
        var oRouter = this.getRouter();
        oRouter.initialize();
        oRouter.attachBypassed(function (oEvent) {
          var sHash = oEvent.getParameter("hash");
          // any subroute is specified and comes from exactly this Display Component ("first")
          // if sHash.indexOf("first") is not checked, multiple Display Components will bypass each other
          if(sHash.indexOf("/")!==-1 && sHash && sHash.indexOf("first")){   
            jQuery.sap.require("sap.m.MessageBox");
            sap.m.MessageBox.show(
             // Message Box Definition as before
             );
          }
        });
      }

    Using this workaround, the application behaves as expected. Nevertheless, if anyone has an idea of how to implement this structure differently, I would be glad if you answer as well.


    Thanks in advance,

    Daniel

    Add comment
    10|10000 characters needed characters exceeded