OpenUI5 / SAPUI5 Communication between controllers – Using Publish and Subscribe from EventBus
Hi SAPUI5 Developers,
In a SAPUI5 application you have probably for every view a controller. In every controller you’ll have functions.
A good developer don’t want to write unnecessary code and reuse coding as much as possible 🙂 Therefore it can be useful to call functions from other controllers.
For example, this could be useful when you’re working with nested views. You could have for example a parent view that exists out of two sub views. In your sub views you want to use a function from you’re parent view.
But there could be a lot of other reason that you want to communicate between controllers.
Therefore SAPUI5 has the EventBus. The EventBus has two functions to set up a communication between controllers:
This function will define an event listener for a specific event.
This function will trigger a specific event
The publish function can be called from everywhere in the project for different events. If there is a subscribe function defined for the triggered event, then it will execute the event handler.
How to use this in your SAPUI5 project?
In my example I’m using a “Main” view that contains a Label, a Button and two sub views.
In the controller of my “Main” view, I have a function to show a message box:
This will result in the following:
Now in the sub views I also add a Label and a Button.
Now I want to use the function of my “Main” view to show the information message from the sub views. Therefore I edit the controller of my “Main” view.
In the “onInit” I define two event listeners with the subscribe function, one for “SubView1” and another for “SubView2”. Both are using the same event handler. They also require a name and an event. I use the name of the view where the event will be fired and the name of the event.
The event handler is the same function that is used for the “Press” event of the Button in the “Main” view. Therefore I have to change this function to make it work for both cases.
I’ve defined event listeners for the buttons on my sub views. But I still need to trigger these events.
To trigger these events I used the publish function of the EventBus in the button press function.
Controller of SubView1:
Controller of SubView2:
I need to use the same name and event as in the subscribe function to trigger the event. It will only call the event handler if these parameters have a match. Additionally I also add parameter with some text.
This will give the following result:
Use the button on the “Main” view
Press the button on sub view 1
Press the button on sub view 2
Important to know, use the unsubscribe function of the eventbus when your app is used in the Fiori Launchpad! Otherwise it will stop working correctly after the following actions:
- Open the Fiori Launchpad
- Go to your app
- Go back to the Fiori Launchpad
- Open your app a second time
This last step will subscribe your function a second time to the eventbus.This will lead to errors.
Add the unsubscribe in the onAfter function, example:
var eventBus = sap.ui.getCore().getEventBus();
Hopefully this is useful.
You can find the full project on Github:
Try out the result:
Great blog on a powerful yet (undeservedly) undervalued feature of UI5 🙂
useful blog thanks for sharing
Good one, help clear the concept of EventBus
I like it! Thank you for sharing. : )
Great, was looking for a short, simple explanation of this concept.
thanks for sharing. Great stuff! Question: I plan to use this for parameter handling during navigation. Will the following scenario work? I mark some entries in view1, take out the values, publish them to the EventBus, navigate to view2, go through onInit(), create subscription and want to use the values in view2. I am in doubt about that a little since view2 is not initialized, when values are published to the EventBus. Are they getting queued and the triggering event as well or will they be lost and the payload wont male it to view2 in this scenario?
Thanks a lot in advance.
I wouldn't use this for sending parameters from one view to another. Therefore I would use routing parameters. If you're sending a full json object to the view I would suggest to use a temporary JSON model to store the json object.
I used temporary JSON model, reason being am using Router concepts for navigation.
And passed and retrieved data using setModel() and getModel() methods respectively.
Thanks for this suggestion.
thanks a lot. After I tried to use router parameters in navTo with sap.m.routing I observed, that the handed over object is not transmitted. It is not appearing in arguments of the routing event I caught on the receiving side. Strange. All examples I found so far working with rewritten router , means own router class implementations. I think I gonna solve the problem with more or less global JSON models which obviously survive context changes during navigation.
I have a question regarding passing of data from one view to another view, using event bus subscription -
Does this event bus publish and subscription works only in case of nested views. ?
I need to pass data from one view to another which are not nested. View 2 is called from View 1, on press of a button, and these two views are not nested.
Could you help me here ?
For passing data from one view to another view you should use dynamic routing. If it's a lot of data that you want to pass, you can create a JSON model in the component for Shared data. Fill this shared model before you navigate and read it in the second view.
What is the best way to pass lots of data from one view to other view. If i pass the data using routing with params the data is all over visible in the url. If i use JSON Model in component the model is getting cleared if i refresh the page. can you suggest some alternate way to tackle this issue.
Hi! i tried to run on url below but it's not working...
It's back up and running!
I think it’s also worth mentioning that we can get event bus from the component
.. which is hooked to the lifecycle of the component rather than from the core. I.e.: When the component gets destroyed (which will be when the user navigates back to the launchpad), then its event bus is also gone –> No need to unsubscribe handlers on exit.
This is also recommended by SAP for apps on FLP.
Also this answer might be helpful for other readers to understand EventBus a bit more: https://stackoverflow.com/a/46186706/5846045
I want to reuse code from one controller in another controller using the EventBus. The problem is that when I register the event handler with "subscribe", it automatically calls the function and I don't want that. I only want to call the function when i publish the event.
...I submitted the comment before my question, so here it is: Do you know how I can stop the subscription of the event to call the actual function?
Normally it shouldn't call the function on subscribe, only on publish. Are you sure you didn't add the brackets when defining your funtion in the subscribe?
Yes, that was it, I forgot the brackets and I didn't see them, it's like I was blind. Thanks!
Very Informative blog on the Important topic of how SAP UI5 Event Bus works.
Issue - The qualty tests for the project fails with a medium priority saying - "Fiori Architectural Guidelines :: Channel is too generic to be used with the event bus in a shell environment, you should rather use your application identifier" - JS_GENERIC_BUS_USAGE.md. This error is coming for the code - "this.bus.publish("flexible", "setDetailPage")".
Can you please let me know if there is any alternative for using - this.publish, considering I want my view to be lazy loaded as my app has more than 10 views. (specially while using Flexible Column Layout, since the explored example also uses event bus way of navigating and adding views.)
Don't think you can do this with the eventbus. I thought views are only loaded the first time you request them... don't understand why you want to change this...
Thank you so much 🙂
Very Useful information!:)