Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
WouterLemaire
Active Contributor

Hi all,

I’m a big fan of the SAP javascript framework called OpenUI5. It’s a big change when you come from WDA but it has a lot more advantages. Besides SAP, there are other Javascript frameworks like AngularJS, BackboneJS, EmberJS, DurandalJS, … . Javascript frameworks are a growing trend in the web/mobile technology.

The idea

I’ve tested a lot of these frameworks. Most of the time I enjoyed working with OpenUI5 of course :smile: . One of the AngularJS plugins that I really like is the Angular UI-Router: https://github.com/angular-ui/ui-router

This plugin has a feature which can change multiple components in the view while navigating as you can see here: https://github.com/angular-ui/ui-router#multiple--named-views

The concept

For example, when surfing to your Javascripte website with the URL pattern #/home, different subviews/components will be loaded in different places (header, menu, content and footer). When you for example navigate to the “Company” page, you will see that the page stays the same. Only the different subviews/components will change.

This is in my opinion a really nice feature! Navigate and change multiple components. Some of the advantages:

  • Reusable components/views
  • One master page with the design
  • Separation of code logic

Standard OpenUI5

I thought this could be a nice feature for OpenUI5. Wouldn’t it be nice if you could navigate in OpenUI5 without changing the whole page but only some parts of it? Yes, indeed. I’ve been looking at the OpenUI5 SDK and I’ve found an OpenUI5 Router component :smile: .

Do you want to take a look? Open UI5 SDK: resources\sap\ui\core\routing.

That’s exactly what I was looking for! Of course this component was not working exactly the same as the AngularJS UI Router, so I did some changes.

I started analyzing the standard OpenUI5 Router component and found out following issues, to have the same feature as in AngularJS Routing you will need to change the following:

  • Only one view definition for an URL pattern possible
  • You can use an URL pattern only once
  • Views have to be created in a parent OpenUI5 component

So in every view you will have to add the required content when maybe you want some parts from the previous page…

An example of how to use a default OpenUI5 Router:


var shell = new sap.ui.ux3.Shell("shell", {
  appTitle:'SAPUI5 Routing Example',
  showLogout: false,
  showLogoutButton: false,
  showSearchTool: false,
  showInspectorTool: false,
  showFeederTool: false,
});
shell.placeAt('content');
var oRouter = new sap.ui.core.routing.Router([{
  pattern: "",
  name: "_main",
  view: "customsapui5.main",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  targetControl: "shell",
  targetAggregation: "content",
  clearTarget: true
},
{
  pattern: "secondPage",
  name: "_secondPage",
  view: "customsapui5.secondView",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  targetControl: "shell",
  targetAggregation: "content",
  clearTarget: true
}]);
oRouter.register("appRouter");
oRouter.initialize();










You have to define a parent OpenUI5 component where the router component will place the views. This can be for example the shell component:

https://openui5.hana.ondemand.com/#test-resources/sap/ui/ux3/demokit/Shell.html

Or you could use layout components like HorizontalLayout:

https://openui5.hana.ondemand.com/#test-resources/sap/ui/layout/demokit/HorizontalLayout.html

Customizing OpenUI5

So what if you want to place your views directly in a DIV container? What if you want to use multiple DIV containers that have to change when you navigate to another page? Why the shell or another parent component?

The Shell component of OpenUI5 is nice, but I like to have some more freedom for creativity.

I’ve started by taking a copy of the OpenUI5 Router component which you can find under the folder:

resources\sap\ui\core\routing --> file: Router-dbg.js

In my OpenUI5 project I’ve created a folder “components”. I placed a copy of the “Router-dbg.js” in it and renamed it to “RouterCustom.js”.

With just one easy change I already had achieved my first goal, I just added changed the parameter “greedy” from “false” to with the value “true” and I was able to navigate multiple views:

The this._oRouter object is an instance of the thirdparty library crossroads. By adding the parameter greedy with value "true", it will function differently. By default this value is false in the crossroads object:

OpenUI5 SDK: resources\sap\ui\thirdparty --> crossroads-dbg.js

By using two DIV’s and a VerticalLayout Component for every DIV as parent I could use multiple parents. With following code I could change multiple components while navigating


var oLayout = new sap.ui.layout.VerticalLayout("oLayout");
oLayout.placeAt('header');
var oLayout2 = new sap.ui.layout.VerticalLayout("oLayout2");
oLayout2.placeAt('content');
var oRouter = new sap.ui.core.routing.Router([{
  pattern: "",
  name: "_header1",
  view: "customsapui5.header1",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  targetControl: "oLayout",
  targetAggregation: "header",
  clearTarget: true
},{
  pattern: "",
  name: "_content1",
  view: "customsapui5.content1",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  targetControl: "shell",
  targetAggregation: "content",
  clearTarget: true
},
{
  pattern: "secondPage",
  name: "_header2",
  view: "customsapui5.header2",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  targetControl: "oLayout",
  targetAggregation: "content",
  clearTarget: true
},
{
  pattern: "secondPage",
  name: "_content2",
  view: "customsapui5.content2",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  targetControl: "oLayout2",
  targetAggregation: "content",
  clearTarget: true
}]);









This is going good but still not exactly what I want. It would be better when you just have to define one pattern for multiple views and to add views directly to a DIV without the parent OpenUI5 component!


While looking deeper in the Router component I came in the “sap.ui.core.routing.Route” component.  Because this component changes the views I definitely needed this one. Took a copy of it and placed it in my OpenUI5 project under the folder components.

resources\sap\ui\core\routing --> file: Route-dbg.js

I also renamed it to “RouteCustom.js”

After some research I came to the conclusion that the most important part for the navigation is  in the method: “_routeMatched”

In this method I’ve added following code:


if(oConfig["views"]){
  $.each(oConfig.views,function(key,value){
  var sViewName = value.view;
  if (value.viewPath) {
  sViewName = value.viewPath + "." + sViewName;
  }
  oView = oRouter.getView(sViewName, value.viewType);
  if(oView && oView["getController"] && oView.getController()["onBeforeShow"]){
  oView.getController().onBeforeShow();
  }
  oView.placeAt(value.div,"only");
  });
}else








With this code I check if there are multiple views for one pattern. If that’s the case I do the following:

  1. loop over the views
  2. get the view name
  3. get an instance of the view by using the Router object
  4. If the view has a method “onBeforeShow” go to that method
    1. This is something I have implemented to do some manipulations before showing the view. This could be handy in some cases, but is not required!
  5. Place the view in the div which you can now add to the configuration of the pattern
    1. The OpenUI5 standard logic of the Route component uses the following statement for placing the div: “oTargetControl[oAggregationInfo._sMutator](oView);” . With this statement you always needed a parent OpenUI5 component. In my code this is replaced by “oView.placeAt(value.div,"only");” so we just need a DIV as parent.

In the “RouterCustom.js” I’ve changed the reference to my custom route component.

Now I could use the Router just the way I wanted


var oRouter = new sap.ui.core.routing.Router([{
  pattern: "",
  name: "_main",
  views[{
  view: "customsapui5.header1",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"header"
  },{
  view: "customsapui5.content1",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"content"
  }]
},
{
  pattern: "secondPage",
  name: "_secondPage",
  views:[{
  view: "customsapui5.header2",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"header"
  },
  {
  view: "customsapui5.content2",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"content"
  }]
});








In my customized router component I can add multiple views to one pattern!

The full package

To get a better picture of how it works and what’s the benefits of this changes are, here an example of how to use.

In my example, I’ve created six views:

One view will be used for the navigation which always will be on the page. All the others I will use for content of the page.

I will create two pages:

First page will exist out of following views/components:

  • Header widget: TitleWidget
  • Left content: GeneralWidget
  • Right content: main

On the second page I will add the following views/components:

  • Header widget: TitleWidget
    • For the title we want to keep the same content as on the first page.
  • Left content: WeatherWidget
  • Right content: WeatherContent

To do this I coded the following in the index.html:


<script>
  jQuery.sap.registerModulePath("sap.ui.core.samples.routing", "./");
     jQuery.sap.registerModulePath('sap.custom.routing.Router', 'components/RouterCustom/');
  jQuery.sap.require("sap.custom.routing.Router");
sap.ui.localResources("customsapui5");
var oRouter = new sap.ui.core.routing.Router([{
  pattern: "",
  name: "_main",
  views:[{
  view: "customsapui5.main",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"content"
  },
  {
  view: "customsapui5.GeneralWidget",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"contentWidget"
  },
  {
  view: "customsapui5.TitleWidget",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"headerWidget"
  }]
  }
  ,
  {
  pattern: "weather",
  name: "_weather",
  views:[{
  view: "customsapui5.WeatherContent",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"content"
  },
  {
  view: "customsapui5.WeatherWidget",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"contentWidget"
  },
  {
  view: "customsapui5.TitleWidget",
  viewType: sap.ui.core.mvc.ViewType.HTML,
  div:"headerWidget"
  }]
  }
  ]);
oRouter.register("appRouter");
  oRouter.initialize();
var oModel = new sap.ui.model.json.JSONModel({ title: "Nested UI Routing in SAPUI5" });
  sap.ui.getCore().setModel(oModel);
  jQuery(function() {sap.ui.template();});
  var view = sap.ui.view({id:"idmenu1", viewName:"customsapui5.menu", type:sap.ui.core.mvc.ViewType.HTML});
  view.placeAt("menu");
</script>









In this code I start loading my customized components, create a router object , set title in my model and add the menu to the menu DIV.

In the index.html I also created my layout with the required DIV’s  for navigation:


<body class="sapUiBody" role="application">
  <div id="overview" class="center">
       <div id="header">
            <div id="headerImage" class="left"><img src="images/sapui5.png"></div>
            <div id="subheader" class="right">
                 <div id="headerTitle" data-type="text/x-handlebars-template"><h1>{{text path="/title"}}</h1></div>
                 <div id="headerWidget" ></div>
            </div>
       </div>
       <div id="menu"></div>
       <div id="main">
            <div id="contentWidget" class="left"></div>
            <div id="content" class="right"></div>
       </div>
  </div>
  </body>




The navigation itself is being handled in the controller of the menu view. With the name of the route, which is defined in the router object, it will navigate to the second page and change all the different parts (as defined in the router object).


goToPage: function(oEvent){
  var oRouter = sap.ui.core.routing.Router.getRouter("appRouter");
  oRouter.navTo(oEvent.getParameter("item").getKey());
  }







Because I use the "NavigationBar" OpenUI5 component for the menu and I use the same name for a route as for the key of "NavigationItem", the key is in the event.


Menu HTML View:


<div data-sap-ui-type="sap.ui.ux3.NavigationBar" data-select="goToPage">
  <div data-sap-ui-type="sap.ui.ux3.NavigationItem" data-key="_main" data-text="User information" ></div>
  <div data-sap-ui-type="sap.ui.ux3.NavigationItem" data-key="_weather" data-text="Weather information" ></div>
  </div>






Result

For the layout I also added some basic CSS..

All the views contain some dummy content just for showing you the principal. In the view “main” I implemented the “onBeforeShow” method, just for showing.

User information page

Weather information page

The title on the index page and the titleWidget are both connected to the same model. Changing the title in the titleWidget will also change the title in the index page.

It looks like it’s a new page but actually there are just three components changed.

You can find the full example on github: lemaiwo/Nested-UI-Routing-OpenUI5 · GitHub

I also added the index and custom components of the router to the attachements

When working with this concept, you are able to do some CSS on the master page (index.html). Therefore you could use other UI frameworks as defined in the following blog:

http://scn.sap.com/community/developer-center/front-end/blog/2014/02/18/openui5-with-bootstrap-for-t...

Hope it's useful!

Kind regards,

Wouter

10 Comments
Labels in this area