Skip to Content
Technical Articles
Author's profile photo Mohammed Imran

Cross app navigation in Fiori Launchpad and restoring SAPUI5 app data using CrossApplicationNavigation service

When you work on multiple custom SAPUI5 apps deployed in SAP Fiori launchpad you often come across a situation where you need to link both the apps by establishing a navigation between them.

Also sometimes only establishing the navigation between the apps is not enough. In some cases you need to save the state of the first app so that when you navigate back, the previous state of the app can be retrieved and can be set to the app so that the user does not lose the previously entered data in the first app.

I recently had the similar requirement in one of my assignment and through this blog post, I want to share my learning about the cross application navigation between SAP Fiori apps along with saving and retrieving of the app state by using CrossApplicationNavigation service of SAPUI5 shell container.

Before diving in the implementation part, I was curious to find out the right approach to meet my requirement without using core model of SAPUI5.

Then I came across John Patterson’s blog post where he had explained the two approaches that can be followed to solve this. Thanks for writing this wonderful blog post 🙂

I tried the 1st approach mentioned in his blog post and was able to achieve my requirement. The same approach I am going to explain here step by step which may help anybody who have the similar requirement.

To demonstrate this let’s create 2 sample SAPUI5 custom apps to show the inter app navigation and the persistence of the data using the app state.

I name my 2 apps as Parent App and Child App. Let’s deploy both the apps in the SAP Fiori Launchpad.

In the Parent App I have a view where I have a simple SAPUI5 form and I have bound a json model (oAddressModel) to the that form as shown below:

this.getView().setModel(new sap.ui.model.json.JSONModel(
				{
					"SupplierName": "New Orleans Cajun Delights",
					"Region": "LA",
					"ZIPCode": "70117",
					"City": "New Orleans",
					"Country": "USA",
					"Tel": "(100) 555-4822",
					"Sms": "123456789"
				}
			), "oAddressModel");

 

The XML view code snippet is simple and as shown below:

<f:Form editable="true">
						<f:title>
							<core:Title text="Address" />
						</f:title>
						<f:layout>
							<f:ResponsiveGridLayout
								labelSpanXL="4"
								labelSpanL="4"
								labelSpanM="12"
								labelSpanS="12"
								adjustLabelSpan="false"
								emptySpanXL="0"
								emptySpanL="0"
								emptySpanM="0"
								emptySpanS="0"
								columnsXL="2"
								columnsL="2"
								columnsM="1"
								singleContainerFullSize="false" />
						</f:layout>
						<f:formContainers>
							<f:FormContainer title="Office Address">
								<f:formElements>
									<f:FormElement label="Name">
										<f:fields>
											<Input value="{oAddressModel>/SupplierName}" id="nameText">
												<layoutData>
													<l:GridData span="XL2 L6 M2 S4" />
												</layoutData>
											</Input>
										</f:fields>
									</f:FormElement>
									<f:FormElement label="Region">
										<f:fields>
											<Input value="{oAddressModel>/Region}">
												<layoutData>
													<l:GridData span="XL2 L6 M2 S4" />
												</layoutData>
											</Input>
										</f:fields>
									</f:FormElement>
									<f:FormElement label="ZIP Code/City">
										<f:fields>
											<Input value="{oAddressModel>/ZIPCode} {oAddressModel>/City}">
												<layoutData>
													<l:GridData span="XL2 L6 M2 S4" />
												</layoutData>
											</Input>
										</f:fields>
									</f:FormElement>
									<f:FormElement label="Country">
										<f:fields>
											<Input value="{oAddressModel>/Country}" id="countryText">
												<layoutData>
													<l:GridData span="XL2 L6 M2 S4" />
												</layoutData>
											</Input>
										</f:fields>
									</f:FormElement>
									<f:FormElement label="Tel.">
										<f:fields>
											<Input value="{oAddressModel>/Tel}">
												<layoutData>
													<l:GridData span="XL2 L6 M2 S4" />
												</layoutData>
											</Input>
										</f:fields>
									</f:FormElement>
									<f:FormElement label="SMS">
										<f:fields>
											<Input value="{oAddressModel>/Sms}">
												<layoutData>
													<l:GridData span="XL2 L6 M2 S4" />
												</layoutData>
											</Input>
										</f:fields>
									</f:FormElement>
								</f:formElements>
							</f:FormContainer>
						</f:formContainers>
					</f:Form>

 

The output of Parent App view is as below when you run the app:

ParentApp

 

I have also created a button (“Press to navigate”) at the page footer of the view and have written the below code to perform inter app navigation to Child App once the user clicks on it.

OnPress

 

The app-state key is generated and appended in the URL as shown below. This key is used to get the app state on navigating back from the child app.

Let’s change the name of the Supplier in the form to “Grandma Kelly’s Homestead” as shown in the below screenshot:

I have kept Child App empty as I wanted to retain the data in the Parent App.

Upon clicking on Fiori Launchpad back button from Child App, it matches the route of the Parent App and the corresponding route matched handler is called.

I have also registered the attachMatched handler of Parent App route in onInit method of the controller file as below:

this.getRouter().getRoute("appView").attachMatched(this._onRouteOrderCreateMatched, this);

And the corresponding handler method is as below:

_onRouteOrderCreateMatched:function(oEvent){
			var sHash = sap.ui.core.routing.HashChanger.getInstance().getHash();
			if(sHash !== "undefined" && sHash !== ""){
				var sAppStateKeys=/(?:sap-iapp-state=)([^&=]+)/.exec(sHash);
				if(sAppStateKeys !== null)
				{
					var sAppStateKey = sAppStateKeys[1];
					sap.ushell.Container
					.getService("CrossApplicationNavigation")
					.getAppState(this.getOwnerComponent(), sAppStateKey)
					.done(function (oSavedAppState) {
						this.getView().getModel("oAddressModel").setData(oSavedAppState.getData());
					}.bind(this));
				}
			}
		}

 

As shown in the above handler method, the saved state object (“oSavedAppState”) is retrieved using the app component and the app state key from the app URL.

I got one issue with respect to my routing where my route was not getting matched and page not found was displaying instead of Parent App view on navigating back from Child App.

I referred the same blog post and found a comment by Jiawei Cao to use optional parameter in the route configurations in the manifest file. Thanks for your comment in the blog, It worked like a charm for me 🙂

I updated my routes with the optional parameter as shown below:

"routes": [
				{
					"pattern": ":?query:",
					"name": "appView",
					"target": "appView"
				},
				{
					"pattern": "nextView",
					"name": "nextView",
					"target": "nextView"
				}
			],
			"targets": {
				"appView": {
					"viewName": "App"
				},
				"nextView": {
					"viewName": "Product"
				}
			}

After doing this change, the back navigation to my Parent App view works successfully and can see my changes persisted in the simple form of Parent App view.

Summary: In this blog post I tried to explain the cross app navigation and app state management while working with custom SAPUI5 apps in SAP Fiori launchpad environment. I hope you found this information helpful and looking forward to your feedback in the comments section below.

 

Assigned Tags

      11 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo ANURAG SINGH
      ANURAG SINGH

      Thank you Imran for sharing this approach in detail.

      Regards,

      Anurag Singh

      Author's profile photo Mohammed Imran
      Mohammed Imran
      Blog Post Author

      Happy to hear that you liked the blog post 🙂

      Author's profile photo Momen Allouh
      Momen Allouh

      Very helpful, I couldn't find any help documentation about AppState so this blog post helped me. ⭐️⭐️⭐️⭐️⭐️

      Thanks.

      Momen

      Author's profile photo Mohammed Imran
      Mohammed Imran
      Blog Post Author

      Thanks Former Member for your feedback. Happy to hear that this blog helped you 🙂

      Author's profile photo Jeroen Vanattenhoven
      Jeroen Vanattenhoven

      I assume that, when 2 apps are registeren on 2 different Fiori Launchpads, this cross application navigation will not work?

      Author's profile photo Mohammed Imran
      Mohammed Imran

      Hi Jeroen,

      I have not tried this with multiple Fiori Launchpads. If you try the same then please post it here or create a blog post out of it so that others also would be benefited..

      Best Regards,

      Imran

      Author's profile photo Tushar Jain
      Tushar Jain

      Thank you Imran for sharing this.

      I am working on sap BTP and have deployed application in BTP through launchpad service.

      Is there a way that we can persist data for cross-app navigation in BTP Launchpad as well ?

      Author's profile photo Mohammed Imran
      Mohammed Imran

      Hi Tushar,

      I have not tried with BTP launchpad. May be if you are able to achieve this in BTP then please share with the community.

      Best Regards,

      Imran

      Author's profile photo Emanuele Matino
      Emanuele Matino

      Hi Mohammed,

       

      thanks for you blog.

      A question: how do you do the initializing of ushell.Container? When I try to use ushell.Container into my controller is always undefined.

      Can you suggest how to avoid an undefined Container?
      I work on Premise gateway with an implemented Launchpad.

       

      Thank in advance for the answer.

      Author's profile photo Mohammed Imran
      Mohammed Imran

      Dear Emanuele,

      Thank you for going through my blog post. I did not face undefined container issue when I was working on the app state. Are you using an older version of UI5 in your application?

      Could you try loading the cross app navigation service using manifest.json file and then use in your controller? Sample code snippet :

      In manifest.json file

      "sap.ui5": {
      		"services": {
      			"CrossApplicationNavigation": {
      				"factoryName": "sap.ushell.services.CrossApplicationNavigation"
      			}
      		}
      }

      In controller file

      var oComponent = this.getOwnerComponent();
      oComponent.getService("CrossApplicationNavigation").then(
      	function (oService) {								  
                 // do your stuff here
      	},
      	function (oError) {
      	   // do some error handling
              }
      );

      Though I have not tried the above approach, you can try and share if it works for you.

      Best Regards,

      Imran

      Author's profile photo Vishnu Kothuru
      Vishnu Kothuru

      Hey Mohammed Imran,

       

      Nice blog thanks. if possible can we achieve this with routing.

      I have two different custom apps, we are navigating from App 1 Object page to App 2 with cross app navigation, till here everything works fine.

      1. List Report with Object page and routing enabled for this.

      2. Another custom App.

      When we enable app state to save the filters in App1 List report screen and move to object page with routing. routing is not working from object page to list report(on Back navigation).

      Can you please let us know how to implement App state from App1 list report-Object page without breaking routing.

      https://answers.sap.com/questions/13666572/app-state-with-routing-not-working-in-sap-ui5-cust.html

       

      Regards,

      Vishnu