In this blog, you will find details about how to build a splitApp mobile application using SAPUI5 and also how to use routing mechanism to navigate between different views. Before reading further please look at the below video, which shows how the final application looks like SAPUI5 splitApp with Routing mechanism – YouTube.Also download the complete project MyRoutingDemo.zip – Google Drive and import into your Eclipse IDE. It helps having the code with you while reading the blog.


I assume that you have basic knowledge of SAPUI5 and developed some basic applications using it in Eclipse. The application has total five JS type views and their corresponding controllers.

-Empty view – No content

-MainView view –  This view holds splitApp control

-Years view – This view displays years

-Categories view – This view displays difference categories like Movie, Actor etc.,

-NomandWinner view – This view displays nominees and winner for a particular category

I have created a JSON file which holds model data. While I am talking about JSON model, I have to mention about website http://www.jsoneditoronline.org/ . I have used this website to create my JSON model, this has very simple editor and you can see JSON file in terms of individual objects in it.

Let’s look at the JSON model data.json file

Here I have given a snapshot of one element of the model

Untitled.png

‘oscars’ node has 5 objects, each one in turn has 2 objects one of them is categories object, which has again 3 objects, where ‘nominee’ is one of them. Nominee object in turn has 3 objects, where each of them has single element called ‘nominee’.  ( I know how you feel after reading this explanation 🙂 sorry for that )

Let’s say I want to read different categories for year ‘2010’, then I have to go to ‘0’ element of array ‘oscars’ and then access ‘categories’ element and then access ‘category’ element. In terms of path definition this can be represented as ‘oscars/0/categories’

If I want to read different nominee for a ‘movie’  category in year 2010 then it will be ‘/oscars/0/categories/0/nominees’

Let’s look at different files in the project I have written comments for each line  in the code so I am not going to explain them here again.

index.html

Router declaration and initialization happens in index.html file.


<!DOCTYPE HTML>
<html>
  <head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
  <script src="resources/sap-ui-core.js"
  id="sap-ui-bootstrap"
  data-sap-ui-libs="sap.m,sap.ui.commons"
  data-sap-ui-theme="sap_bluecrystal">
  </script>
  <!-- only load the mobile lib "sap.m" and the "sap_bluecrystal" theme -->
  <script>
  sap.ui.localResources("Views");  //Folder where views JS files are stored
  jQuery.sap.require("sap.ui.core.routing.Router");  // load Router module
  jQuery.sap.require("sap.m.routing.RouteMatchedHandler");  // load RouteMatchedHandler module
  //Initilaize the MainView
  var app = sap.ui.view({id:"idMainView1", viewName:"Views.MainView", type:sap.ui.core.mvc.ViewType.JS});
  //Place the MainView content in "Content" Area
  app.placeAt("content");
  // Create an instance of Router class
  var oRouter = new sap.ui.core.routing.Router(
  {
      rcategories: {  //Route 'rcategories' takes you from the current view to view 'Categories'
          pattern: "oscars/{year}",  // This pattern is placed after the hash('#') symbol in URL
                                      // varaible inside {}, 'year' in this case is replaced with value later
                                      // in method itempressed() inside controller of 'Years' view
          view: "detail.Categories",  // This is the target view, to where navigation happens
  },
  rnomwinner: {    //Route 'rnomwinner' takes you from the current view to view 'NomWinner'
  pattern: "nominees/{year}/{cat}",  // This pattern is placed after the hash('#') symbol in URL
      // varaible inside {}, 'year' and 'cat' in this case are replaced with values later
                                      // in method itempressed() inside controller of 'Categories' view
  view: "detail.NomWinner"  ,        // This is the target view, to where navigation happens
  }
  },
  {
  targetControl: "splitapp",      // targetControl refers to the id of control where all the target views are to be placed
                                  // this is defined in 'MainView' createcontent method
  targetAggregation: "detailPages", // targetAggregation refers to aggregation namw of targetControl. For splitApp
                                  // control there are two Aggregations, 'detailPages' and 'masterPages'
  viewType: "JS",  // viewType defines type of the target views
  viewPath: "Views",  // The view path parameter specifies a prefix that prepends the target views. In our case
                    // target view detail.Categories will be takes as Views.detail.Categories. Please note that
                    // view Categories is placed under folder Views/detail/
  clearTarget: false  //The clear target parameter defines a boolean that is used to specify if the aggregation
                      //should be cleared before adding the view to it.
  });
  var oRouteHandler = new sap.m.routing.RouteMatchedHandler(oRouter);
  oRouter.register("router");  // Assign a name to Router, so that we can access it in all controllers by using this name
  oRouter.initialize();  // Initialise the Router
  </script>
  </head>
  <body class="sapUiBody" role="application">
  <div id="content"></div>
  </body>
</html>






Years View


createContent : function(oController) {
// Create a standardlistitem control by binding 'title' property with element 'year' of the JSON model
  var oItemTemplate = new sap.m.StandardListItem({title : "{year}", type : sap.m.ListType.Active});
// Create 'List' control having 'oscars' node of model as binding to 'items' aggregation and add a
// eventhadnler method ( 'itempressed' method in controller) to 'itemPress event. This event gets triggered
// whenever user press a Listeitem
  var oList = new sap.m.List({
  items : {path:"/oscars", template:oItemTemplate},
     itemPress : function(oEvent){
  oController.itempressed(oEvent);
  }
  });
// Add List control to a new Page control and return it
  var oPage = new sap.m.Page({
  title: "Years",
  content: [oList]
  });
  return oPage;
  }
});

Year view Controller


// This method gets triggered whenever a item in the List is pressed. Here we trigger
// navTo() method of Router to initiate the navigation
itempressed: function(oEvent) {
   // Get instance of router
   this.oRouter = sap.ui.core.routing.Router.getRouter("router");
// Get Array if all items in List control
   var a = oEvent.getSource().getAggregation("items");
// Get reference to current Listitem that has been clicked
   var b = oEvent.getParameters().listItem;
// In order to know the position of the clicked Listitem with in the List
// we loop over all items and compare each Listitem with the clicked Listitem
   for (var i = 0; i < a.length; i++) {
  if (a[i] == b) {
  break;  // we have a match so exit the loop. At this point 'i' refers to index of clicked Listitem
  }
   }
// Call navTo() method of Router class to trigger the navigation
// For route "rcategories' pattern is defined as 'oscars/{year} where 'year' is a variable
// which needs to be repalced by a value. Here we are replacinf it with the index of Listitem
// that has been clicked by user
   this.oRouter.navTo("rcategories", { year : i });
   }
});

Categories View


createContent : function(oController) {
// Create a standardlistitem control with id 'idlistitem' and  by binding 'title' property with element
// 'category' of the JSON model
var oItemTemplate = new sap.m.StandardListItem(this.createId("idlistitem") , {title : "{category}", type : sap.m.ListType.Active});
//Create 'List' control with id 'idlist' and add a
//eventhadnler method ( 'itempressed' method in controller) to 'itemPress event. This event gets triggered
// whenever user press a Listeitem
var oList = new sap.m.List(this.createId("idlist"), {
itemPress : function(oEvent){
oController.itempressed(oEvent);
  }
  });
//Add List control to a new Page control and return it
var oPage = new sap.m.Page({
  title: "Categories",
  content: [oList]
});
return oPage;
  }
});

Categories View Controller


onInit: function() {
// Get instance of Router
  this.oRouter = sap.ui.core.routing.Router.getRouter("router");
// Call 'attachRouteMatched method,which defines a function that gets called everytime
// a 'RouteMatched' event is triggered by application
  this.oRouter.attachRouteMatched(function(oEvent) {
// get the name of the Route
   var sRoute = oEvent.getParameter("name"),
// Get the name of the target view
       oView = oEvent.getParameter("view");
// As this method gets called for all routes defined in the application we  have to
//make sure that code gets executed only for the route that we are interested in
if(sRoute == "rcategories")
{
// Define the binding path
var spath = "/oscars/" + oEvent.getParameter('arguments').year + "/categories";
// Bind aggragation 'Items' of List with above defined path pass listitem with id 'idlistitem' as template
oView.byId("idlist").bindItems(spath, oView.byId("idlistitem"));
}
   });
  },
itempressed: function(oEvent) {
      //Get the instance of Router
   this.oRouter = sap.ui.core.routing.Router.getRouter("router");
  //Get the instance of HashChanger
   this.oHasher = sap.ui.core.routing.HashChanger.getInstance();
   //Get the current hash value in the URL and split the URL at character '/'
   // if the hash value is 'oscars/2', then below statemnet will split that into
   //'oscars' and '2'. we are interested in element with index 1 i.e. second element in array 'j'
   var j = this.oHasher.getHash().split("/")[1];
   // Get all instances of Listitems present in List
   var a = oEvent.getSource().getAggregation("items");
   //Get instance of Listitem which user has clicked
   var b = oEvent.getParameters().listItem;
   //To get the index of the Listitem that has been clicked loop over the array of Listitems
   // and compare with clicked listitem that is 'b'
   for (var i = 0; i < a.length; i++) {
  if (a[i] == b) {
  break;  //we have a match so exit the loop
  }
   }
  //navigate to Route 'rnomwinner'. pass values to variables 'year' and 'cat' in patter 'nominees/{year}/{cat}'
   this.oRouter.navTo("rnomwinner",  { year : j , cat : i});
   }
});

NomWinner view


createContent : function(oController) {
// Create a standardlistitem control with id 'idlistitem' and  by binding 'nominee' property with element
// 'category' of the JSON model
var oItemTemplate = new sap.m.StandardListItem(this.createId("idlistitem"), {title : "{nominee}", type : sap.m.ListType.Active});
//Create 'List' control with id 'idlist'
  var oList = new sap.m.List( this.createId("idlist"));
//Create a Button control with id 'idbutton' and add an eventhandler method 'click' of controller
// to action 'press'
  var oButton = new sap.ui.commons.Button(this.createId("idbutton"),{
  width : "300px",
  height : "100px",
  style: sap.ui.commons.ButtonStyle.Accept,
  press : function(oEvent) {
  oController.click(oEvent);
  }
  });
//Add List control and Button control to a new Page control and return it
  this.page = new sap.m.Page({
  title: "Nominees and Winner",
  navButtonText: "Back",
  showNavButton: true,
  navButtonPress: [oController.onNavButtonTap, oController],
  content: [oList, oButton]
  });
  return this.page;
  }
});

NomWinner view Controller


onInit: function() {
// Get instance of Router
   this.oRouter = sap.ui.core.routing.Router.getRouter("router");
// Call 'attachRouteMatched method,which defines a function that gets called everytime
// a 'RouteMatched' event is triggered by application
   this.oRouter.attachRouteMatched(function(oEvent) {
// Get the name of the Route
   var sRoute = oEvent.getParameter("name"),
// Get the name of the target view
   oView = oEvent.getParameter("view");
// As this method gets called for all routes defined in the application we  have to
//make sure that code gets executed only for the route that we are interested in
   if(sRoute == "rnomwinner")
  {
// Define the binding path
   var spath = "/oscars/" + oEvent.getParameter('arguments').year + "/categories/" + oEvent.getParameter('arguments').cat + "/nominees";
// Set the button text back to original value every time user clicks on new category
   oView.byId("idbutton").setText("And the Winner is....");
// Bind aggragation 'Items' of List with above defined path pass listitem with id 'idlistitem' as template
   oView.byId("idlist").bindItems(spath, oView.byId("idlistitem"));
  }
   });
  },
click: function(oEvent){
//Get the instance of HashChanger
   this.oHasher = sap.ui.core.routing.HashChanger.getInstance();
//Split the hash value at '/'. this will give you an array with individual values
   var j = this.oHasher.getHash().split("/");
//Get the value of element 'winner' in JSON model at a given path
   var winner = sap.ui.getCore().getModel().getProperty("/oscars/"+j[1]+"/categories/"+j[2]+ "/winner");
//Set the value of property 'text' of button with value of 'winner'
   this.getView().byId("idbutton").setText(winner);
  },
// Navigate previous entry in browser history
//This function is called when user clicks on back button in detail view
onNavButtonTap : function()
  {
  window.history.go(-1);
  }
});

I would like to discuss more about how routing works rather than explaining how the different views are built. Let’s divide the routing into different parts and analyse each part in detail.

1 – Definition and initialization of Routes

Routes definition consists of giving a name to the route, name of the target view and pattern value if needed.Now there are three statements that we need understand

sap.m.routing.RouteMatchedHandler(oRouter) –   Create an instance of RouteMatchedHandler class. Inside the constructor, two standard methods are attached to  two events ‘RouteMatched’ and ‘RoutePatternMatched’. These method handle the placement of the target view based on the configuration parameters ‘targetControl’ and ‘targetAggregation’ if the view needs to be placed in masterPages or ‘detailPages’

oRouter.register(“router”) – Registers the router to access it from another context. Use sap.ui.routing.Router.getRouter() to receive the instance, bu passing ’router’ as the value.

oRouter.initialize() –  Attaches the router to the hash changer. In this method we create instance of sap.ui.core.routing.HashChanger and attach event handler function to event ‘hashChanged’.

2-  How navigation happens using routes

In any event handler method inside the controller of source view we should call method “navTo” of class sap.ui.core.routing.Router. In our case to navigate to ‘Categories’ view we use below code in event handler method ‘itempressed’ inside controller of view ‘Years’

  this.oRouter.navTo(“rcategories”, { year : i });

Here first parameter takes name of the route and second parameter is used to fill in the variables  in the ‘pattern’ property of the specific route. Route rcategories has pattern ‘oscars/{year}’. Here variable ‘year’ is replaced with value ‘i’ and this pattern is placed after ‘#’ in the URL. When I click on 2011, value after # is changed to ‘oscars/1’ as shown below.

Capture.JPG

Similarly if we click on ‘Actress’, itempressed() method in controller of view ‘Categories’ is called and there we have the below code

this.oRouter.navTo(“rnomwinner”,  { year : j , cat : i});

If you look at the definition of Route ‘rnomwinner’ ( nominees/{year}/{cat }), we see two variables ‘year’ and ‘cat’. So in the ‘navTo’ method we pass values to these two variables. Below is how the URL looks once we click on any of the category

Capture.JPG

Now let’s look at how navTo() method actually works. below is the call stack ( I have added only important methods )

Method Class
navTo() – Initiates the navigation to target view sap.ui.core.routing.Router
setHash – change hash value to new value sap.ui.core.routing.HashChanger
fireHashchanged – fire event ‘HashChanged’ sap.ui.core.routing.HashChanger
RouteMatched(Inside this method ‘Createcontent()’ method of the target view is called) sap.ui.core.routing.Route
fireRoutematched – Fire event ‘RouteMatched’ sap.ui.core.routing.Router
attachRouteMatched – In this method we can write custom logic on what to do when hash value matches with a ‘pattern’ value of certain route ( for example, bind a property of control with an element /collection of model. In our case we bind the aggregation ‘items’ of ‘List’ control with ‘categories’ node) In target view controller ( in our case it is placed in oninit() method of target view controller

So to summarize navTo() method results in following

  • Set the hash value to new value
  • Find out all the routes that have pattern value which matches with the new hash value. Once we have match, fire ‘routematched’ event, which calls all ‘attachroutematched’ methods

Please note that I am no way an expert on SAP UI5, all that is presented here is done by reading/exploring stuff on my own. If there are any mistakes or blunders that I did, please feel free to comment. I really appreciate that.

Thanks for reading my blog and keep sharing 🙂 🙂

To report this post you need to login first.

15 Comments

You must be Logged on to comment or reply to a post.

    1. s sin

      Hi sankara,

      Thanks for your good documents, but I face with a problem, when I want to run my app.

      Control with ID mainApp could not be found – EventProvider sap.ui.core.routing.Target

      mainApp is the id of my Splitapp.
      can you please help me what can be the problem?

      (0) 
  1. swapnil mhadlekar

    hello i m trying to develop a splitApp using odata services. i got the data in list in master view, but i m stucked on detail view part. I have used xml views for this app. for detail view part i m using another odata service when a item is clicked passing the key data in url. can i get any help?

    (0) 
  2. swapnil mhadlekar

    i am using the following odata service passing the key data as:

    http://eccehp7.erp.com:8000/sap/opu/odata/sap/ZSM_CUSTOMER_SRV/CustomerSet('C000001‘)

    i am getting the data in xml format as below:

    <title type=”text>CustomerSet(‘C000001’)</title>
    <updated>2017-01-23T05:45:47Z</updated>
    <category term=”ZSM_CUSTOMER_SRV.Customer scheme=”http://schemas.microsoft.com/ado/2007/08/dataservices/scheme/>
    <link href=”CustomerSet(‘C000001’) rel=”self title=”Customer/>
    <content type=”application/xml>
    <m:properties>
    <d:CustomerId>C000001</d:CustomerId>
    <d:CustomerName>TCS</d:CustomerName>
    <d:City>VIKROLI</d:City>
    <d:Url>http://www.tcs.com</d:Url>
    <d:Zip>400086</d:Zip>
    </m:properties>
    </content>
    </entry>
    i have created a form in detail view.
    I dont know how to use this data in detail view.

     

    (0) 

Leave a Reply