Skip to Content

How to enable the share option and persist current application state in a UI5 application

In standard Fiori apps using Fiori elements the Share feature is available. This feature is also enabled by default if we use the List report Application template provided in Webide. It has two options (when there is no Jam integration) ‘Send Email’ and ‘Save as Tile’.

In this blog I will share my experience how we implemented it for a custom UI5 Application which uses XML views and Java Script controllers.

Getting it on user interface was the easy part. We added a button on the initial View which on press opens up a fragment with 2 options. We used a normal button sap.m.Button for ‘Send Email’ and AddBookmarkButton control from sap.ushell.ui.footerbar for ‘Save as Tile’ option.

<OverflowToolbar id="tool">
	<ToolbarSpacer/>
	<Button press="onPressShare" icon="sap-icon://action"/>
</OverflowToolbar>
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:foot="sap.ushell.ui.footerbar">
	<Popover showHeader="false" placement="Bottom" >
		<VBox class="sapMPopoverCont">
			<Button text="Send Email" press="onPress" iconFirst="true" icon="sap-icon://email"/>
			<foot:AddBookmarkButton id="book" text="Save as Tile" title = "Maintenance Notification" showGroupSelection = "true"/>
		</VBox>
	</Popover>
</core:FragmentDefinition>

 

onPress: function(oEvent) {
	sap.m.URLHelper.triggerEmail("", "Link to Maintenance Notification", window.location.href);
}

 

But for the functionality to work correctly we had to somehow persist the current app state so that when we click on the saved tile or the email link we see the same context.

How to do it ?

  1. Use Navigation Handler to store the inner app state. Our Application had a Smart Filter and a Smart table on the first view so that users can search for appropriate record/s. As soon as a filter criterion is entered and we search for entries we save the app state.
    onSearch: function(oEvent) {
    
    	var oTable = that.oView.byId("smartTable");
    	var oFilt = that.oView.byId("smartFilterBar");
    
    	var mInnerAppData = {
    		selectionVariant: oFilt.getDataSuiteFormat(),
    		tableVariantId: oTable.getCurrentVariantId()
    	};
    
    	that.oNavigationHandler.storeInnerAppState(mInnerAppData);
    
    }​

Here we have selection variant which captures the filter which are set on screen and we save it in Inner App data.

On calling storeInnerAppState we will notice the URL will automatically change and a parameter will be added similar to this –

?sap-iapp-state=ASFLPLTWYA4IFMGQ1CG58TQG5SFZNXJYHI4QANW8

Note : We will have to define the navigation handler in the controller to use it. 

  1. Add a new Route in manifest file to accommodate handing of URLs with parameter “sap-iapp-state” –
    "routes": [
        {
            "pattern": "",
            "name": "notificationList",
            "target": "notificationList"
        },
        {
            "pattern": ":?sap-iapp-state:",
            "name": "notifListQuery",
            "target": "notificationList"
        }
    ],
    "targets": {
    		"notificationList": {
    			"viewPath": "XXXXX.view",
    			"viewName": "NotificationList",
    			"viewLevel": 1
    		}
    }

   If this is not done we will get an error because the first view has no pattern attached to it –

  1. Add a new data source in manifest and point it to standard Odata service INTEROP where the internal app data is stored –

 

  1. Add a model with any name, (we used the name GlobalContainers) so that we can make an Odata call to fetch the stored context. 

 

  1. Finally in the init method of the initial view we incorporate logic to read the app state id and set the saved app data before the first view is loaded. for doing this we parse the app state id from the URL and pass it to the global oData service to retrieve the saved app data. Then we set the appropriate view elements.
    onInit: function() {
    			
    	var controller = this;
    	this.oNavigationHandler = new NavigationHandler(this);
    	that = this;
    	var oView = this.getView();
    	var appStateKey = "";
    	var url = window.location.href;
    	var i = url.search('sap-iapp-state');
    
    	if (i > 0) {
    		i = i + 15;
    		appStateKey = url.substring(i);
    	}
    
    	if (appStateKey) {
    		var url1 = "/GlobalContainers('" + appStateKey + "')";
    		var oModel = this.getOwnerComponent().getModel('GlobalContainers');
    		var that1 = this;
    		var functionSucess = function(oData, controller) {
    			sap.ui.core.BusyIndicator.hide();
    			var oFilt = that1.getView().byId("smartFilterBar");
    			var obj = JSON.parse(oData.value);
    			oFilt.setDataSuiteFormat(JSON.stringify(obj.selectionVariant), true);
    		}
    
    		var functionError = function(oError) {
    			sap.ui.core.BusyIndicator.hide();
    			var test = oError;
    		}
    
    		sap.ui.core.BusyIndicator.show();
    		var params = {
    			success: function(oData, controller) {
    				functionSucess(oData, controller);
    			},
    			error: function(oError) {
    				functionError(oError);
    			}
    		};
    
    		oModel.read(url1, params);
    	}
    }​

 

Regards, Saurabh

10 Comments
You must be Logged on to comment or reply to a post.
  • Hi Saurabh,

    Very nice blog.

    I have one query here. In point 3, you have specified that we require an Odata service INTEROP where the internal app data is stored. Is this service also available in the fiori launchpad provided in cloud foundary?

    • Thank you Anubha,

      I have tried this standard service with the on premise back end. If you deploy the your apps on launchpad which is on SAP cloud (Portal service) it will work because the your app is still pulling data from SAP back end only. You would have to use cloud connector to connect to back end though. If we are talking about SAP public cloud, I would guess it should work but I did not get a chance to test it till now. Maybe you an try it out and share your experience.

      Regards,

      Saurabh

    • Hey Soumya,

      That was the first thing that I tried but it did not work out. I wanted to build the share option which is available by default in applications which are built using the smart templates provided by SAP Webide and also apps using the fiori 2.0 controls(like list report and object pages) in a traditional UI5 app. This blog lists down the steps I followed for implementation.

      Regards,

      Saurabh Sharma

  • Dear Saurabh,

    Thank you for this guiding approach to handle app state on UI5!
    Can you say if using the uishell service “CrossApplicationNavigation” can do the same as “NavigationHandler”?

    I figured out that invoking methods on “CrossApplicationNavigation” generates AppState object (and its key), but does not seem to persist anything. I think I should see any data being persisted, right?

    Any tipps or comments are welcome! 🙂

    Yours, Thomas

    • Hi,
      I think under the hood NavigationHandler is making use of  the ‘CrossApplicationNavigation’ Service. When I was trying to implement state handling for our apps, I faced the situation that save methods are not saving the context to any service and when we tried to retrieve any context, we got HTTP status code 403 – forbidden.

      Solution: Turn on option ‘Save App State Data’ under Fiori Launchpad Administrator Page -> Settings -> System Settings.

      After that, app states are working as expected!

       

      Saurabh Sharma This might be worth an update of your post?

      • Hi Alexander,

        Thank you for your reply.

        In our app, I use “CrossApplicationNavigation” service and its method “createEmptyAppState” to store the app’s state via its component.

        And that was the solution for me, I did not need to turn any options on in the FLP anyways.

        It is great to use this ushell service to persist state in an Fiori App and to create/use a tile for persisting/re-initialization.