Nathan Hands' Blog

UI5 applications consultant, entrepreneur, fantasy book lover and gamer

How to move data between views in UI5

4 years ago · 6 MIN READ
#tutorial  #UI5 

Disclaimer

I wrote the majority of this blog several months ago but only just finished it up recently after a long break in writing. If you have any topics you'd like me to cover to give me some inspiration then please let me know on Twitter.

Introduction

One of the most common problems that I see in UI5 applications is the improper passing of key data between various routes/ views within the application.

In this blog I want to go over a few different methods of passing data between your views in a nice and clean way. All options are viable though I prefer some over others.

The router variable

The most common and typically best way to pass data between two views is the use of a router variable which you might also know as a parameter. The router variable can be defined in our manifest inside of the "routers" section and under the "pattern" for each route.

Inside of the pattern you give your router variable a name, this is how you can access the variable later and acts as a key-value pair.

Our Manifest

Screenshot 2019-04-15 at 11.46.08.png

So as we discussed above I've setup our routing in our manifest and I have assigned a route for our detail page. This detail page has inside of its parameter a variable name of 'taskId' which will be present in my URL when passing this data.

Passing taskId from our main view

First we need to get our taskId or primary ID that we want to pass, typically this will be from something like a list or a table of options that you want to select from or maybe simply a form where you're asking the user for the ID to search into.

To make life easier I'm going to pretend that I'm selecting the item from a table, but inside of each row of that table I have a button to view more details. So my onPress method would look something like this:

onPressViewMoreDetails: function(oEvent){
    var bindingContext = oEvent.getSource().getBindingContext("myItems"); //myItems is a local model
    var selectedObject = bindingContext.getObject(); //returns the object of the selected item
    var taskId = selectedObject.Id; //Id is the primary key that we want to pass to our next view
    this.getRouter().navTo("taskDetails",{
    "taskId" : taskId
    });
},

Note, the get router function is actually one that is commonly defined inside of UI5 projects but if not then it is as shown below:

getRouter: function(){
    return sap.ui.core.UIComponent.getRouterFor(this);
}

Getting taskId in our detail view

To get the data that we passed we would first setup our controller to catch the route of 'taskDetails' in one of our lifecycle events such as "onInit" as seen below:

onInit: function () {
    this.getRouter().getRoute("taskDetails").attachMatched(this.onRouteMatched, this);
},

This will call the function of 'onRouteMatched' each time we hit the route as defined in our manifest. This means that we can access our parameter/ argument via the use of the oEvent as seen below:

onRouteMatched: function (oEvent) {
    var oArguments = oEvent.getParameter("arguments");
    var sTaskId = oArguments.taskId;
}

oArguments is an object of our key/value pairs that we had in our route and so we can access the string of TaskId as seen in our above function. This could now be used to get data from our backend about that specific task and would be a nice shareable link that would look something like http://localhost/webapp/#/detail/1/ where "1" is the variable passed.

Key information about the router variable

The router variable should be the requires ID fields to trigger your oData call, so if I had an entity set where I needed a taskId to retrieve our task then I should pass just that taskId and nothing more.

The idea of passing this variable is so that you can get the data from the backend again, if you have 2 or even 3 id fields that are needed for your entity set then these are fine to pass as different router variables. Simply add in more variables.

Do NOT however use this method to pass things such as settings between views or user specific variables such as their username or pernr. Think about this data as being user agnostic.

The best part about storing these key fields inside of the URL is that we give our users a nice shareable link to give to colleagues which is generally speaking invaluable for making an application that makes our users happy and effective at their job.

The global JSON Model

The global JSON Model is simply a client side JSON Model that is defined at the global level of the application. It works exactly the same as if we defined a local json model inside of a view/ controller but is accessible across multiple controllers.

So think of it like the OData model in terms of accessibility but with the functionality of a local JSON Model which essentially just gives us a nice place to store a load of data. There are a few reasons why you might want to do this, sometimes the backend isn't ideal and so you might need to store some things from earlier calls, sometimes you might want to store some prior selections so users can go back and forth between views without losing some key filters? Whatever the reason you're bound to have one for passing/ keeping some persistent data between views that isn't relevant to a router variable.

The manifest

Inside of our manifest.json we need to setup a new model in our 'models' section and we simply define the type as 'sap.ui.model.json.JSONModel' and the dataSource name we've defined elsewhere.

Screenshot 2019-06-11 at 11.55.31.png

The dataSources section is defined inside of the sap.app section of our application and here's the example of mine here:

Screenshot 2019-06-11 at 11.58.58.png

As you might notice my 'settingsModel' has a uri that references a .json file so that I can pre-populate some data or at least setup my keys for later insertion of data but this isn't necessary.

Accessing the data

As I said before this works exactly the same as if you defined the local JSON Model inside of the controller, the name of the model will be whatever name you gave it inside of the 'models' section so in our case 'settingsModel'.

So inside of any controller of this UI5 application I can use the normal methods of accessing the model through var oSettingsModel = this.getView().getModel('settingsModel');

See the other methods for accessing and setting data inside of the SAPUI5 documentation.

Local storage

Local storage is a persistent storage of key/value pairs that will never expire and could be accessible for years after the initial creation if never cleared. This isn't an often used method for storing data as I don't often need data for such a long period of time, if this is a similar case for you I suggest you read on towards the explanation of session storage.

Placing values inside of local storage

Setting data into local storage is easy and can be achieved with just 1 line as below:

localStorage.setItem("taskId", "1")

The above will set the value of "1" into the key of "taskId" and this will then be accessible in the local storage store.

retrieving items from the local storage

To get items out of the local storage this is also as simple as a single line which can be found below:

localStorage.getItem("taskId")

This will retrieve the value found inside of the local storage as found under the key of 'taskId' which is what we set above.

note

all items stored inside of local storage are done so as a string and will need to be converted when we retrieve the item.

Session Storage

Session storage works just the same as local storage except that once the user closes the tab the values stored inside of session storage are gone. This is more useful to me than local storage as there's often no reason to store items unneccesarily inside of the local storage in my opinion but your requirements might be different and so that's why I mention them both.

Getting and setting strings to the session storage is the same as the local storage except you use the word of 'sessionStorage' in place of 'localStorage' with examples below:

sessionStorage.setItem("taskId", "1");

sessionStorage.getItem("taskId");

Wrap up/ comparrison of the options

Above are 4 (okay probably really 3) ways of storing and retrieving data in ways that we can access that data between various views of our application. I typically always use router variables for passing our key values between views, this is because you create a link that is shareable with our users and refreshing the page will not cause problems.

The global JSONModel is one I would typically use for passing large amounts of data between views, the problem with this is that this information is lost upon refresh of the application/ closing of the tab and so should only be used with that idea in mind.

The localstorage should be used for persisting some data between sessions, a rare requirement in my experience but it certainly has it's place but we start getting towards the use of storing things for offline use which should be done via things such as WebSQL (well okay, maybe not but it's the only blog I have on offline storage and it works... just about)

Session storage is just a worse version of using the global json model as we can only store strings and so I almost never use this and prefer the use of the global json model.

Conclusion

Use router variables where possible, it's the best method of passing data between views and is shareable between more than one user. Just keep the use to a minimum and only pass key fields that are used to retrieve data from the backend.

···

Nathan Hand

SAP Applications consultant working as a UI5 developer, Lover of automation, technology, fantasy books & games.
comments powered by Disqus


Proudly powered by Canvas · Sign In