Skip to Content
Technical Articles

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.

 

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