Friday, August 16, 2013

How to pass parameters between your App parts?

With SharePoint web parts developers had an option to make them communicate with each other using standardized set of interfaces called connection interfaces that allowed Web Parts to exchange information with each other at run time. (Creating a Connectable Web Part)

In the new SharePoint App model, web parts are replaced with app parts. The problem is they don't have an equivalent to Web Part Connections. So how can you pass parameters from one part to another?

To answer this you have to consider several things:
  • App parts are basically small applications that are presented in your SharePoint site through iframes
  • each app is running in a separate domain and so are their app parts. Because of this any direct manipulation through some javascript code is out of the question because it would mean cross-domain scripting and all you would get is an "access denied" message
Thankfully there is a solution for this that is provided through HTML5 and the postMessage method.
This method provides a way for communicating between browsing contents in HTML documents.

To demonstrate this I will use Napa tools with my SharePoint Online to create two App parts, one to send a message and the other one to receive it.

Although theoretically you can achieve app parts to communicate directly with one another I found it a much better choice to add additional code to the page where my app parts are located (using script editor for example) and make the communication go through there.
                     
So first lets send a message from one of our app parts.

Using Napa tools I will create a new App (I named it SenderApp). Add this following JavaScript function to its ClientWebPart.aspx page.

function sayHello()
  {
   var appMsg = {
      'msg':'Hello from sender app part'      
  };
  
  window.parent.postMessage(appMsg, "*");
  }


In this function we have created an object appMsg that contains only a variable called msg with some text. Similarly you can define your own  app object that you wish to share with other apps or SharePoint. As we know our app part will run in an iframe on our SharePoint site so we can use  window.parent.postMessage to post that object to the SharePoint page on which we have placed our app part.

To execute my function I added a button to my app part that calls it on click.
<button id="bttPost" onclick="sayHello()">Say Hello</button>

This is the end result for my SenderApp part:



Now for the app part that will receive this message. Again using Napa tools I have created another app (I called it ReceiverApp). In this app we will add a listener that will wait for a message that will come from other sources using this following script.

window.addEventListener("message", receiveMessageInApp, false);
function receiveMessageInApp(event)
{   
divMsg=document.getElementById('divMessages');
divMsg.innerHTML= divMsg.innerHTML+event.data+'<br/>';
}
So to catch the message from our app part we will use window.addEventListener that looks out for incoming messages and calls receiveMessageInApp function when it picks one up. It would be a good practice to send some additional information in your post message object, so you can check which part (if more of them sends messages) posted a message. Also you can use event.origin to see that.
receiveMessageInApp  method is used to display the data we will receive through messages.
This is how my part looks in the end:



Now you can package both of your apps, deploy them to your SharePoint site and add the app parts to a page. On the same page add a script editor. In that editor we will catch the message sent from our sender app part, process the message and forward it to our receiver app. Here is how my page looks like after I add all the parts:


Add the following script to your script editor to process messages from the sender app and forward them to your receiver part.
<script>

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event){
procesHello(event.data.msg);
}

function procesHello(msgData){
var iFrame = document.getElementsByTagName("iframe")[1];   
iFrame.contentWindow.postMessage(msgData,"*");
}

</script>
So in my script editor I am first listening for a message to arrive and then I am searching in my page for the second iframe element (or the second app part) and forwarding data of that message to its window(you will probably want to check for the id or something else that defines the iframe of the app part to which you wish to send your data to). If everything is correct, when you press Say Hello button, you should see that the message was processed in the ReceiverApp part.



From this simple example we see how we can achieve communication between app parts using postMessage
So one app part sends a message to the parent page, the page receives the message and sends it of to another app part if needed.

The only limitation is it will not work on older browsers since this is a HTML5 feature but other then that this is a very effective way to achieve app parts communication.