Hi folks,

This blog mainly explains about navigating and parameter passing between two views.

Below is the Project directory.

directory.PNG

Steps to follow

1. Create an SAPUI5 Application Project.

INDEX.HTML

index.PNG

2. Create a JS file named Component.js and place it inside WebContent folder.


(It mainly comprises of four steps :Configuration, Initialization,Access and view ownership)



jQuery.sap.declare("sap.ui.demo.Component");
sap.ui.core.UIComponent.extend("sap.ui.demo.Component", {
  metadata : {
  routing : {
  config : {
  viewType : "JS",
  viewPath : "routingdemo",
  targetControl : "NavContainer",
  clearTarget : false,
  },
  routes : [
  {
  pattern : "", // which appears in URL, while you navigate
  name : "first",     // Name that is used in navTo method
  view : "FirstPage",   // this is the target view that you are navigating to
  viewPath : "routingdemo", // path of the target view
  targetAggregation : "pages" // this defines whether the target view is a [pages/content/masterpages/detailpages]
  },
 {
  pattern : "InSecondPage",
  name : "second",
  view : "SecondPage",
  viewPath : "routingdemo",
  targetAggregation : "pages"
  },
 ]
  }
  },
 init : function () {
 // 1. some very generic requires
  jQuery.sap.require("sap.m.routing.RouteMatchedHandler");
  jQuery.sap.require("sap.ui.demo.MyRouter");
  // 2. call overridden init (calls createContent)
  sap.ui.core.UIComponent.prototype.init.apply(this, arguments);
// 3a. monkey patch the router
  var router = this.getRouter();
  router.myNavBack = sap.ui.demo.MyRouter.myNavBack;
  // 4. initialize the router
  this.routeHandler = new sap.m.routing.RouteMatchedHandler(router);
  router.initialize();
  },
  destroy : function () {
  if (this.routeHandler) {
  this.routeHandler.destroy();
  }
  // call overridden destroy
  sap.ui.core.UIComponent.prototype.destroy.apply(this, arguments);
  },
  createContent : function () {
  // create root view
  var oView = sap.ui.view({
  id : "app",
  viewName : "routingdemo.App",
  type : "JS",
  });
var oModel = new sap.ui.model.json.JSONModel();
    
      oModel.setData(
      {
       myName : null,
        myPass : null
      }
    
      );
    
oView.setModel(oModel);
return oView;
  }
});


3. MyRouter.js (Custom Router)




jQuery.sap.declare("sap.ui.demo.MyRouter");
sap.ui.demo.MyRouter = {
  /*  * to monkey patch the router with the mobile nav back handling
  */
  myNavBack : function (route, data) {
  var history = sap.ui.core.routing.History.getInstance();
  var url = this.getURL(route, data);
  var direction = history.getDirection(url);
  if ("Backwards" === direction) {
  window.history.go(-1);
  } else {
  var replace = true; // otherwise we go backwards with a forward history
  this.navTo(route, data, replace);
  }
  },
};


4. Create an App View .


App.view.js ( In app.view we usually have a sap.m.App or sap.m.SplitApp depending upon the requirement)




sap.ui.jsview("routingdemo.App", {
  /** Specifies the Controller belonging to this View.
  * In the case that it is not implemented, or that "null" is returned, this View does not have a Controller.
  * @memberOf routingdemo.App
  */
  getControllerName : function() {
  return "routingdemo.App";
  },
  /** Is initially called once after the Controller has been instantiated. It is the place where the UI is constructed.
  * Since the Controller is given to this method, its event handlers can be attached right away.
  * @memberOf routingdemo.App
  */
  createContent : function(oController) {
  this.setDisplayBlock(true);
  return new sap.m.App("NavContainer");
  }
});


4. Create FirstPage View

a) FirstPage.view.js  Basic page which accepts two inputs( Name and password) on click of a button, we call a navigate function , which is wriiten in the controller part.


sap.ui.jsview("routingdemo.FirstPage", {
  getControllerName : function() {
  return "routingdemo.FirstPage";
  },
  createContent : function(oController) {
  var flexbox=new sap.m.FlexBox({direction:"Column"});
  flexbox.addItem( new sap.m.Input("name",{placeholder:"Enter UserName" value : "{/myName}"}));
  flexbox.addItem( new sap.m.Input("password",{placeholder:"Enter Password" value : "{/myPass}"}));
  flexbox.addItem( new sap.m.Button('login',{text:"Log In",
   press:function()
   {
   oController.navigate();
      }
    })
  );
  flexbox.setAlignItems("Center");
  flexbox.setJustifyContent("Center");
                  
  var page1 =new sap.m.Page({
       title: "Routing Demo",
       content:flexbox,
       });
            
  return page1;
}
});




b) FirstPage.Controller.js



(In controller we get the instance of the router in the init method and use it to navigate to the specific page. we pass the parameters between the views by using an object and binding to a modelname. We use navTo method to navigate)




sap.ui.controller("routingdemo.FirstPage", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* @memberOf routingdemo.FirstPage
*/
  onInit: function()
  {
  this.router = sap.ui.core.UIComponent.getRouterFor(this);
  },
    navigate : function()
    {
 
  this.router.navTo("second");
  }
});



5. Create SecondPage View

a) SecondPage.View.js ( We can get the object in the model and use it in secondpage view ie object.myname )  object is userdefined.


sap.ui.jsview("routingdemo.SecondPage", {
  getControllerName : function() {
  return "routingdemo.SecondPage";
  },
  createContent : function(oController) {
 var flexbox=new sap.m.FlexBox({direction:"Column"});
  flexbox.addItem( new sap.m.Text({text : "{/myName}"}));
  flexbox.addItem( new sap.m.Text({text : "{/myPass}"}));
  flexbox.setAlignItems("Center");
        flexbox.setJustifyContent("Center");
                  
        var page2 =new sap.m.Page({
                       
                            content:flexbox,
                            showNavButton: true,
                            navButtonPress: function(){ oController.handleNavBack(); },
                       
        });
            
        return page2;
   
}
});


b) SecondPage.controller.js ( we navigate back by using myNavBack method ,  which we have defined in our MyRouter.js , which is a custom Router)


sap.ui.controller("routingdemo.SecondPage", {
  onInit: function() {
  this.router = sap.ui.core.UIComponent.getRouterFor(this);
  },
  handleNavBack : function(){
  this.router.myNavBack("first");
}
});


And the final output .


You can see the change in the URL,(InsecondPage). You can navigate Back by clicking on the back icon.



firstpage.PNGsecondpage.PNG



Hope this Blog helps.


Regards


Indrajith

To report this post you need to login first.

23 Comments

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

  1. Rutika Bodas

    Hi Indrajith,

    Its a good blog; though I am not too clear on the relevance of the concept of ‘routing’. I have read routing related blogs, but still not clear on the utility of it.

    What i mean is say, if I want to navigate from one page to any other page in my app, I could just say app.to(“next_page_id”) and that would do it for me. This way, there will not be any change in the app URL either.

    Hence, I fail to understand the significance of routing, though I am sure it is something useful. Just not sure when and why so.

    Could you brief up why do we use routing when we can navigate across pages without it as well?

    Regards,

    Rutika Bodas

    (0) 
    1. indrajith patel Post author

      Hi Rutika,

      Thank you for going through the Blog.


      Routing is the recommended and most preferred method for SAPUI5 applications. The main advantage of using Routing is that it provides you an ability to bookmark a particular navigation state . However app.to/panel works fine to navigate, It will have an effect on the performance when you have more number of views. You can go through the below SAPUI5 SDK – Demo Kit

      to get much idea about routing.



      Regards

      indrajith

      (0) 
  2. Robin van het Hof

    Although I like your blog — but could you please reformat the code for better readability? — it contains one big error…

    Upon clicking the navigate button in the first page, you retrieve the input controls’ values, store it in a model.

    When displaying the second page, you retrieve the model, and set the text control’s ‘text’ property to the value from the model’s inner property. This is a real bad pattern, it doesn’t use databinding, and as such it’s not how models should be used!

    To use proper databinding, your code should be more like this:

    1) Inside your Component.js, or first page controller, define a global JSON model:

    var oModel = new sap.ui.model.json.JSONModel();

    oModel.setData({

       myName : null,

       myPass : null

    });

    sap.ui.getCore().setModel(oModel);

    2) In the first page controller, your navigate function should be just this:

    navigate : function()

        // removed all the model creation stuff here

        this.router.navTo(“second”);

    }

    3) Now, in the first view, apply the data binding to the input controls:

    flexbox.addItem( new sap.m.Input(“name”,{value : “{/myName}” }));

    flexbox.addItem( new sap.m.Input(“password”,{value:”{/myPass}”}));

    4) Then, in the second view, you can simply use this:

    flexbox.addItem( new sap.m.Text({text : “{/myName}”}));

    flexbox.addItem( new sap.m.Text({text : “{/myPass}”}));

    NB: If your intention was to show how you could pass data between two views without using a shared model, a much better approach would be to use the EventBus, and have the first view publish an event and have the second view subscribe to that event.

    (0) 
    1. indrajith patel Post author

      Hi Robin,

      Thank you for your valuable inputs.

      I tried using two data binding before posting the blog itself, but it does’nt seem to work.

      So i choose the other one.

      The two way data binding seems to work when i don’t include the component.js file,where i write the routing configuration in index.html . could you please provide some inputs on the same.

      regards

      Indrajith

      (0) 
      1. Robin van het Hof

        I tried using two data binding before posting the blog itself, but it does’nt seem to work.

        So i choose the other one

        Ok, but the way it is written now is really incorrect, and IMHO no UI5 developer should connect controls like this to a model (I call it connecting since this is not databinding)

        The two way data binding seems to work when i don’t include the component.js file,where i write the routing configuration in index.html . could you please provide some inputs on the same

        For me to comment on that I should see the original code. Having a Component.js and a two-way binding model is how most of the UI5 applications are built, so it should work just fine. Maybe you can post a topic on the forum with the code which isn’t working

        (0) 
  3. Kedar Tingikar

    Hi Indrajith,

    I appreciate your efforts in putting in this blog however I completely agree with Robin van het Hof on the bad pattern of moving data using another model.

    As suggested by Robin, in your navigate method pass the arguments along with the routes name. Arguments would be part of the pattern.

    Also in your SecondPage.controller.js in onInit() method use the route instance(router) methodattachRouteMatched or attachRoutePatternMatched to get the arguments passed in Navigate method of FirstPage. More info on these methods – SAPUI5 SDK – Demo Kit

    I think the key for routing and navigation would be Pattern Matching

    (0) 
    1. indrajith patel Post author

      Hi kedar,

      Thank you for going through the blog and sharing your inputs.

      You suggested to pass the arguments along with the routes name. But if that is the case, then those parameters will be visible in the URL right? Don’t you think there might cause some security issues. And what if i want to fetch 10 values from a textfield and then pass it to the next view. At that time the URL looks clumsy.

      Regards

      Indrajith

      (0) 
      1. Kedar Tingikar

        Agreed.

        But the ultimate location to launch the application is either the Fiori Launchpad(on the browser) or Fiori Client(on the mobile) you will not see the parameters.

        (0) 
    2. Robin van het Hof

      As suggested by Robin, in your navigate method pass the arguments along with the routes name. Arguments would be part of the pattern.


      Actually, I was referring to using the EventBus, and not passing arguments via the URL pattern 😉 . I agree with Indrajith this isn’t a viable approach for passing more than two arguments.


      See the Application Best Practices guide, chapter Routing for more details on how to use the EventBus

      (0) 
      1. Kedar Tingikar

        But the document says, a new navigation technique is introduced which superseded EventBus:

        Per the documentation:

        A new Routing mechanism was introduced to UI5 in release 1.16. For in-app navigation, this supersedes previous techniques such as using the

        sap.ui.core.EventBus

        or sharing navigation-container specific controller code amongst aggregated pages.

        And recommends using other techniques for Intra-application navigation:

        While these previous techniques work well for intra-application navigation, they don’t cater for the requirements for bookmarking and resuming application User Interface (UI) state.

        I am missing something?

        (0) 
        1. Robin van het Hof

          Well, I’m not using the EventBus for Navigation itself — which is indeed rightfully deprecated — but you for passing chunks of data while navigating with a router — which is still supported, see the Application best Practices

          Another way of course is to use a global model, which is available to all views in an application

          (0) 
  4. indrajith patel Post author

    Hi Robin,

    I have updated the blog based on your inputs. I have used Two-way data binding and i works fine..!!  Thanks for your valuable inputs.

    Regards

    Indrajith

    (0) 
  5. bhaskar kuntla

    Hi Indrajith,

    If i put ClearTarget as  TRUE in the router defination i’e in component.js it is showing some error that

    Unable to get property ‘getId’ of undefined or null reference “.


    Regards,

    bhaskar.

    (0) 
    1. indrajith patel Post author

      ClearTarget : true means it will clear the target aggregation before we add the views. So you should not clear the target aggregation.Set it as false

      (0) 
      1. bhaskar kuntla

        Thanks for the quick reply Indrajith,

        As per the my requirement i have to clear the target and i need to append the view again since view content will change dynamically

        (0) 
  6. chetna dabra

    Hie Indrajeet,

    Can you help me out with following routing issue?

    I have written menuBar code inside a fragment, (there is a fragment folder created inside web content, and inside this folder menu.js file contained). Now i call this fragment in one of my views successfully, but when i click on menu item  so as to navigate to another view, it gives me following routing error:

    cannot read property navTo of undefined.

    I have created component.js file exactly like yours, giving routes of my views.

    On select event of menu bar itemi call one of the controller functions as follows:

            var quickMenuItm1 = new sap.ui.commons.MenuItem({text:”Place Order”,

                   select :function(oEvent) {

                       sap.ui.controller(“demo.dashboard”).handleOrder();

            },

            });

    Though function gets called successfully, it does not navigate to another view instead gives me above mentioned error.

    Code for the function inside controller:

      onInit: function() {

      this.router = sap.ui.core.UIComponent.getRouterFor(this);

    }


    handleOrder:function(evt) {

      this.router.navTo(“orders”);

      },

    I think its not able to find router, but i do not understand why? without using fragment when i called the same function from view it worked, then why not here?

    Can you please help?

    Thank you,

    Best Regards,

    Chetna

    (0) 

Leave a Reply