Skip to Content

Interop

Routing and Event System for UI5

This is a library for UI5 that allows many instances of UI5 applications to run simultaneously, integrated or independently of each other in sub-containers (side by side, or embedded)

Container applications can register their container locations so that any app can navigate to a chosen container (eg: Left/Right/Header/Footer/Main/Master/Other)

It also provides methods for communicating between those applications (simplified version of EventBus, for ease of use)

What can you use it for?

Use your imagination! but here’s a few examples, you can use this to compare two client records (instantiate the same fiori view twice, side by side, with different route params) Or even run completely different applications independently in the same window (for example, your Inbox in a side or top panel, so you can keep track of your job queue at all times)

Why not just use ComponentContainers?

Flexibility, Simplicity, and Routing.

Even if you were to use ComponentContainers, how do you route them? how do you maintain two route url’s on the one page? these problems are solved in my Interop solution.

And all apps that run this way, can be built in the usual UI5 way with standard routers. So all of your existing UI5 apps can be run in containers, and any new apps you build using Interop can still run as standalone applications when necessary. (aka: no dependency or tight coupling!)

Why did I build this?

I’ve seen a few attempts at building ‘frameworks’ that could dynamically call upon different UI5 applications, and I thought I could do better, so I gave it a shot. What bugged me most about these solutions I saw, was that any app or view used in them would follow a very custom pattern and was usually tightly-coupled. I wanted to do it in a reliable way, a standardised way, one that didn’t require re-training of staff to be able to use it, so any ui developer could write a standard app and it would work within it.

I also thought it would be a very cool thing, to be able to run an Inbox application as a slide in panel, while also being able to compare two records side-by-side, and have process flows tracked in a header, etc etc. So… here we are.

Limitations / Assumptions

It it assumed that all applications using Interop use two word namespaces. eg: “product.app” if this isn’t the case you will run into trouble. This is the namespace convention I’m used to working with and have personally seen the most, which is why I’ve built it in this way. It could be made configurable, but you’d still need to at least be consistent (eg: 3 names is fine, but ALL apps would need to be 3 names)

Download

The Interop Library can be found on GitHub: https://github.com/LordOfTheStack/UI5-Interop-System

 

Now, Let’s jump right in…

Ok, so that’s the introduction / text-book stuff out of the way! I’ll show you what this little thing can do.

I’ve created a sample container application, which is included in the Git repository. It is fully featured, I’ve not even utilised all the panels I’ve setup in it, so it should serve well as a starting point for most use cases.

In my example I’ve created a split-app, and one other additional app, and am demonstrating how views from the split-app can be instantiated multiple times side by side for record comparisons.

Here’s a few screenshots of me playing around with the panels.

select a record

expand the right hand panel

click ‘move’ button on the right hand panel

tick duplicate and apply (so that content on the main panel will be duplicated into the right side as a new instance)

select a different record in the master list (which will update just our main content panel)

click an action that performs a navigation, and see that only the relevant panel is affected

I could go on and on, but I think this is enough to demonstrate what’s going on.

Additionally to what i’ve done here, it should be noted that demoapp1 (this master/detail app) can be run in standalone mode, from its own index page. Even the inter-app routing has fallback routines to facilitate this. Try it for yourself.

Live copy (HCP account required) https://ui5interopsystem-p1942037524trial.dispatcher.hanatrial.ondemand.com/sample/container/index.html

 

How it works

Merged URL Route Patterns

You may not have noticed it at first, but the URL in this app has a querystring of “?nav=”

This parameter is generated by Interop, and is a combined version of every panels current route pattern (for example, there’s two client records, so each instance of that view needs different parameters fed into its onRouteMatched event handler).

You’ll also notice that it’s hard to read… that’s because I’ve implemented string compression, to keep it from getting too long. It also has the added advantage of discouraging users from messing with the url. However, if you would like it to be more readable, you can turn off Url Compression.

These constructed URL’s allow the users session to be maintained, so if they hit F5 to refresh the page, it will remember what to load. Likewise they can copy&paste the URL into an e-mail and the correct configuration of views will be loaded when the recipient clicks it.

While this could’ve been done automatically, I have designed this to be triggered by the container application, for reasons that will become obvious soon..

In the container app you’ll notice these little pieces of code for maintaining sessions

//this allows the Interop system to manage browser history 
Interop.setRestoreOnBrowserBack(true);
var sessionResult = Interop.restoreSession();
if(!sessionResult.restored) {
     //no existing route info, this is a blank run
	updateUrl: function() {
		if(this._loaded) {
			//save the session, and add additional session states (the state of expansion of the panels)
			//by doing this, we enable the page to be refreshed with f5 or the url to be copied & pasted into another browser, without losing track of what's in each panel
			Interop.saveSession({
				me: window._masterOpen || false,
				re: this.oLayoutData.RightPanelOpen,
				rw: this.oLayoutData.RightPanelBig
			});
		}
	},

You may have already gathered, that the container gets the opportunity to add its own custom session variables, these will be encoded into the ?nav= URL string along with the base information. (in this sample, it is used to remember the expanded state of the master and right hand panels)

The container also controls what to do if a session isn’t present (in this case, my sample container looks for normal ui5 route parameters to see if an app has been specified, and load it, if not, it defaults to demoapp1)

The setRestoreOnBrowserBack(true) is simply a necessity because browser events will be hooked when this is called. This allows the user to press the back button in their browser and have their session restored automatically by Interop

 

Virtual Router Objects

To allow legacy routing (apps running standalone OR within containers) without further development effort inside the app, virtual (or proxy) routers are created on the fly by Interop to simulate commonly used functionality of the standard SAP router classes.

This means that when you call this.getRouter() you are getting a dummy object, that will simply translate your standard .navTo requests into Interop navigateContainer calls automatically.

These virtual routers also handle onRouteMatch events, and will parse in all the same parameters you would usually expect, along with a few new ones (like “container”, telling you which container you’re in)

To use virtual routers, simply inherit the dalrae.ui5.BaseController in all your view controllers. Or, copy its .getRouter function into your own base.

	onBeforeRendering: function() {
		//fallback routing support (allows apps to run standalone and still call .navigateContainer) -PhillS
		if(dalrae.ui5.routing.Interop.UseFallbackRouting) {
			dalrae.ui5.routing.Interop.mFallbackRouter = this.getRouter();
		}
	},
		
	// supports our Interop component containers method of routing -PhillS
    getRouter: function() {
    	//UPDATED to work with manifest style apps -PhillS
	    var router = sap.ui.core.UIComponent.getRouterFor(this);
	    if(!router || dalrae.ui5.routing.Interop._cc ) {
	    	if(dalrae.ui5.routing.Interop._cc[dalrae.ui5.routing.Interop.StandardContainer.Main] || !router) {
		    	var router2 = dalrae.ui5.routing.Interop.getRouterFor(this);
		    	if(router2) {
		    		return router2;
		    	}	
	    	}
	    }
		if(dalrae.ui5.routing.Interop.UseFallbackRouting) {
			//fallback routing support (allows apps to run standalone and still call .navigateContainer) -PhillS
			dalrae.ui5.routing.Interop.mFallbackRouter = router;
		}
	    return router;
    },

Essentially, the standard routers are totally overwritten by Interops own routing code, which is designed to emulate the sap router as closely as possible. Of course, some methods might be missing from my version of the router, and if this is an issue for your implementation you may need to extend the class yourself (or let me know).

 

Globally Registered Containers

Each area of the screen that is route-able, is registered as a container.

This means that the container app, and the contained app, do not need to know each other.

They simply need to know container id’s, such as “main” and “master” to interact, so neither are coupled or dependant upon each other to operate.

The easiest way to do this is to just use the dalrae.ui5.routing.Container element in your XML view and assign it one of the standard id’s.

However, you can use any UI element that has a <content> aggregation. To do so, you can call Interop.registerContainer()

Interop.registerContainer( Interop.StandardContainer.Main , oPanel );

or

<mvc:View xmlns:routing="dalrae.ui5.routing">
<routing:Container name="master" />

 

Container Navigation

Inter-app navigation is highly simplified. rather than constructing deeplink urls, you can navigate a container to a completely different applications view by simply using the navTo parameters for that view.

//demonstrating an Interop cross app navigation.
Interop.navigateContainer( Interop.StandardContainer.Main , {
    app: "sample.demoapp2",
	nav: [
        "main",
	    { example: "an example parameter" }
	]
});

The only addition is the container ID, and the app namespace.

Although it is also worth noting, that namespaces must be registered before being used.

This is needed in Gateway/Launchpad systems, which use SemanticObjects. But in Hana you’ll still need to do it (until I come up with a clever way to autodetect Hana systems that is)

//Registering a namespace in Hana
Interop.registerNamespace("sample.demoapp1");

//Registering a namespace in Gateway
Interop.registerNamespace("sample.demoapp1","ZDEMOAPP1");

The added perk of doing this, is that the master list can remain loaded as app1, while the main content panel can navigate off to app2, so the user doesn’t need to go back a screen in order to access another record from app1, which is far less disruptive to the user flow of the program.

 

Global Event System

As mentioned, a replacement to the EventBus system is provided. It works in basically the same way. My main motivation for doing this was to make the event signatures consistent with all other elements of UI5, which the event bus isn’t.

To use it, you can register event handlers in any view of any app, and fire those events from anywhere as well.

I haven’t really used much of these in my sample, but they are useful for when you’d like your applications to actually be able to talk to each other. There’s plenty of things you can achieve by having panels communicate. You could for example, have an event fired each time the main panel opens a client record, and have the header panel pop down with alerts or available actions for that client number, regardless of which app that client is being viewed in.

Also, the Interop navigation fires off a few inbuilt events that you can take advantage of, and these, are in fact being used in my Sample so you can see them in action.

OnNavigate: This event is fired when any container is navigated anywhere. So any program listening to this event will see the navigation of every other program. This is good for container applications which may want to show or hide certain panels.
Parameters:
app : app namespace (eg: “sample.demoapp1”)
name : route name
arguments : routing parameters
container : ID of the container (eg: “main”)
sessionRestore : true/false

OnContainerCleared: This event is fired when any container has its content cleared via clearContainer, clearAllContainers, or a session restore.
Parameters:
container : ID of the container (eg: “main”)
sessionRestore : true/false

OnSessionRestored: This event is fired when a route pattern is successfully or unsuccessfully restored from a URL or custom source via the restoreSession() call
Parameters:
restored : true/false
navs : internal data of the session
extraStateInfo : custom values included in the session

 

Flexible Layout

Just to re-iterate… you can create any container application layout you like.
Just be sure to use the standard container id’s (or if making your own, be consistent) and it will work just fine. You can even have multiple container apps if you like. The sample I have provided is precisely that, a sample, and I haven’t even used it to it’s full potential in this example.

It actually has many active panels ready to go (diagram below)

But as stated, just a sample, so go nuts, make your own, go crazy!

 

Conclusion

I don’t know how many of you will utilise this system, but I thought it was worth sharing, as it’s the kind of functionality I’d like to see available out-of-the-box.

Being able to compare two client records, and giving users the choice to move content around, is something I’m eager to see, there’s many cool things I can think of that become possible. Additionally, the applications I’ve tried running in this way, have (in my opinion) run much smoother, since you never need to reload the entire screen.

I’ve uploaded the code to GitHub with an MIT license, so you are free to use it yourself

 

Download

The Interop Library can be found on GitHub: https://github.com/LordOfTheStack/UI5-Interop-System

To report this post you need to login first.

Be the first to leave a comment

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

Leave a Reply