Technical Articles
Analytics Designer tips and tricks: Communicating between embedded applications and host web pages using the Post Message API
There is a scenario that comes up fairly often; embedding. SAP Analytics cloud applications support JavaScript post messages and it can be used to communicate in both directions; both from the host html5 app into the SAC app and from the SAC app to the containing webpage. It is often just a simple “we need to run this app in an iframe”. It can be more sophisticated, however. Suppose you want to access a non-ODATA REST service. Or suppose your catalog of apps are small tiles, meant to communicate with each other via the central web page. Etc., etc. That’s where the POST message API becomes very useful.
Post Messages in a Nutshell
This post won’t delve into the basic JavaScript Post Message in detail. I’ll leave that to other sources, such as the Mozilla developer docs.
To pass a message from the host webpage to the SAP Analytics Cloud app, you’ll want to want to get the contentWindow property of the iFrame. With that, you can pass your message, using the postMessage() method. This will fire the onPostMessageRecieved event in the app, with that message. The message can be whatever you want, as long as it works with the structured clone algorithm. In our example, we’ll just be passing a text string, “Hello World”. You can obviously mass more complicated structures, such as JSON objects or whatever data structures you wish to invent.
To pass a message from the app to the containing web page, you’ll need to do two things. Firstly, you’ll need to edit your webpage JavaScript scripting to add an event listener for message to the window element and script that event handler. In the app, you’ll use the Application.postMessage() script command to send your message from the app to the parent web page.
Example
The app that we’ll be embedding is very simple. It contains three text elements, Text_1, Text_2 and Text_3. It contains one input field, InputField_1. It also has a button, Button_1.
Text_1 = The label for Text_2
Text_2 = Where our post message will be going
Text_3 = The label for InputField_1
InputField_1 = Where the user will write the text to send back to the web page
Button_1 = Which will actually send it.
The app has two scripts, one in onPostMessageRecieved and one in the button’s onClick event. onPostMessageRecieved has two parameters; message and origin. The message parameter is the one that you’ be sending from the web page. The origin parameter is the domain and port of the host web page that it is coming from. We’ll ignore origin and simply post the message to Text_2:
Text_2.applyText(message);
In the button’s onClick event, you’ll get the value of whatever the user typed into InputField_1. Then you’ll use Application.postMessage() to send it out. This script method has three parameters:
PostMessageReviever – (either PostMessageReviever.Parent or PostMessageReviever.Top). This is the hierarchical html DOM order of the recipient (direct parent, or top). In our simple example, they will be the same thing.
message – Our message
targetOrigin – We can use this parameter to restrict sending post messages to specific domains. In our simple example, where we are not worried about security, we’ll just use “*”, to allow everything.
var messageToSend = InputField_1.getValue();
Application.postMessage(PostMessageReceiver.Top, messageToSend, "*");
You can use the share button to open the application sharing dialog and get the embedding url for your application.
Our host webpage will also be minimalistic. It will consist of the 2×2 table, and an iFrame. The first row of the table will hold some text telling the user to click on a button to send a text message to the app. The second column will hold that button. The second row will contain the response and a label for that response. The iFrame will contain the app.
The JavaScript will also be minimalistic. The button’s on click event will get the contentWindow of the iFrame and then send “Hello World”
function sendMessageToSAC() {
var theIFrame = document.getElementById('theIFrame').contentWindow;
theIFrame.postMessage("Hello World","https://appdesign.eu10.sapanalytics.cloud");
}
The window object will get an event listener for message. The assigned script will find the table cell that will hold the message from the app and display it.
window.addEventListener("message", receiveMessageFromSAC, false);
function receiveMessageFromSAC(event) {
var responseElement = document.getElementById('response');
responseElement.textContent = event.data;
}
Altogether, the containing webpage is about 30 lines of generously pretty printed html and JavaScript:
<html>
<body>
<table>
<tr>
<td>Click to send "Hello World" to app</td>
<td>
<button onclick="sendMessageToSAC()">Send</button>
</td>
</tr>
<tr>
<td>Response = </td>
<td id="response"></td>
</tr>
</table>
<iframe id="theIFrame"
src="https://appdesign.eu10.sapanalytics.cloud/sap/fpa/ui/tenants/5c065/bo/application/571D82EA222811C3D005E820D0B79393?mode=embed"
height="500"
width="1000">
</iframe>
<script>
function sendMessageToSAC() {
var theIFrame = document.getElementById('theIFrame').contentWindow;
theIFrame.postMessage("Hello World","https://appdesign.eu10.sapanalytics.cloud");
}
window.addEventListener("message", receiveMessageFromSAC, false);
function receiveMessageFromSAC(event) {
var responseElement = document.getElementById('response');
responseElement.textContent = event.data;
}
</script>
</body>
</html>
From there, you can click on the button in the webpage to display “Hello World” in the SAP Analytics world application and you can enter text in the app and click the button there to display it in the host webpage. That’s all there is to basic message exchanging in embedded apps! Feel free to experiment and come up with your own uses for embedding + post message exchange.
Hi David!
Just to let you know that I am reading your blog and it is absolutely fantastic! Thanks a lot to share your knowledge!
Javier