How to create connected SharePoint Hosted App Part using Visual Studio

Manoj Kumar Mittal
 
SharePoint Developer
March 15, 2015
 
Rate this article
 
Views
9883

As SharePoint developers very well know, data can be shared between web part using SharePoint 2010 using standardized set of interfaces called connection interfaces that allowed Web Parts to exchange information with each other at run time.

More info on creating a Connectable Web Part can be found here

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:

1. App parts are basically small applications that are presented in your SharePoint site through Iframes

2. 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, post Message and Event Listener method.

http://msdn.microsoft.com/en-us/library/windows/apps/hh441295.aspx

http://msdn.microsoft.com/en-us/library/ie/ff975245(v=vs.85).aspx

These method provides a way for communicating between browsing contents in HTML documents.
To demonstrate this I will take one scenario i.e.

I will create two SharePoint Hosted AppPart using Visual Studio, First one is Sender App and second one is Receiver App

Both Apps having Client Web Part (Host Web) and List Definition with default data

SenderSHAppPart having List Employee Data

ReceiverSHAppPart having List Department Data

image

                                Fig 1.1

Create Sender SharePoint Hosted App using Visual Studio

Project Structure as per below Fig 1.2

Right Click on the Project and Add two new items: – Custom List name Employee Data and Client Web Part name SenderAppPart.

image

Fig1.2

Adding Default Data to List

image

image

 

Fig 1.3

Add HTML and Script to SenderAppPart.aspx

 <script type="text/javascript">
   
   'use strict';
   
   function OnChange() {
     
     var myindex = D1.selectedIndex
         
         var SelValue = D1.options[myindex].text
             
             var appMsg = {
               
               SelValue: SelValue
               
             }
     ;
   
   window.parent.postMessage(appMsg, "*");
   
   return true;
   
 }
   
 </script>

HTML

 <div id="Success">
   
   <select class="select" id="select-reviewer" name="D1" onchange='OnChange();'>
   </select>
   
 </div>
 
 <div id="error">
   
 </div>

Add Script file SendData.js to Script folder and refer it in SenderAppPart.aspx

   'use strict';
   
   var hostweburl;
   
   var appweburl;
   
   var employeeData;
   
   // This code runs when the DOM is ready and creates a context object which is needed to use the SharePoint object model
   
   $(document).ready(function () {
     
     //Get the URI decoded URLs.
     
     hostweburl =
       
       decodeURIComponent(
         
         getQueryStringParameter("SPHostUrl")
         
       );
   
   appweburl =
     
     decodeURIComponent(
       
       getQueryStringParameter("SPAppWebUrl")
       
     );
   
   // resources are in URLs in the form:
   
   // web_url/_layouts/15/resource
   
   var scriptbase = hostweburl + "/_layouts/15/";
   
   // Load the js files and continue to the successHandler
   
   $.getScript(scriptbase + "SP.Runtime.js",
               
               function () {
                 
                 $.getScript(scriptbase + "SP.js",
                             
                             function () {
                               $.getScript(scriptbase + "SP.RequestExecutor.js", execCrossDomainRequest);
                             }
                             
                            );
                 
               }
               
              );
   
 }
                  );
   
   // This function prepares, loads, and then executes a SharePoint query to get the current users information
   
   // Function to prepare and issue the request to get
   
   //  SharePoint data
   
   function execCrossDomainRequest() {
     
     // context: The ClientContext object provides access to
     
     //      the web and lists objects.
     
     // factory: Initialize the factory object with the
     
     //      app web URL.
     
     var context = new SP.ClientContext(appweburl);
     
     var factory =
         
         new SP.ProxyWebRequestExecutorFactory(
           
           appweburl
           
         );
   
   context.set_webRequestExecutorFactory(factory);
   
   //Get the web and list objects
   
   //  and prepare the query
   
   var web = context.get_web();
   
   var list = web.get_lists().getByTitle("EmployeeData");
   
   var camlString =
       
       "<View><ViewFields>" +
       
       "<FieldRef Name='Title' />" +
       
       "<FieldRef Name='DepartmentId' />" +
       
       "</ViewFields></View>";
   
   var camlQuery = new SP.CamlQuery();
   
   camlQuery.set_viewXml(camlString);
   
   employeeData = list.getItems(camlQuery);
   
   context.load(employeeData, "Include(Title , DepartmentId)");
   
   //Execute the query with all the previous
   
   //  options and parameters
   
   context.executeQueryAsync(
     
     successHandler, errorHandler
     
   );
   
 }
   
   // Function to handle the success event.
   
   // Prints the data to the page.
   
   function successHandler(data, req) {
     
     var enumerator = employeeData.getEnumerator();
     
     while (enumerator.moveNext()) {
       
       var employeedetail = enumerator.get_current();
       
       var departmentId = employeedetail.get_item("DepartmentId");
       
       var employeeName = employeedetail.get_item("Title");
       
       populateUsersDropDown(employeeName, departmentId);
       
     }
   
 }
   
   function populateUsersDropDown(employeeName, departmentId) {
     
     $('#select-reviewer').append("<option value='" + departmentId + "'>" +
                                  
                                  employeeName + "</option>");
   
 }
   
   // Function to handle the error event.
   
   // Prints the error message to the page.
   
   function errorHandler(data, error, errorMessage) {
     
     document.getElementById("error").innerText =
       
       "Could not complete cross-domain call: " +
       
       errorMessage;
   
 }
   
   // Function to retrieve a query string value.
   
   // For production purposes you may want to use
   
   //  a library to handle the query string.
   
   function getQueryStringParameter(paramToRetrieve) {
     
     var params =
         
         document.URL.split("?")[1].split("&");
   
   var strParams = "";
   
   for (var i = 0; i < params.length; i = i + 1) {
     
     var singleParam = params[i].split("=");
     
     if (singleParam[0] == paramToRetrieve)
       
       return singleParam[1];
     
   }
   
 }

Create Receiver SharePoint Hosted App using Visual Studio

image

Fig 1.4

image

Fig 1.5

Add div tags to Receiver App Part

 <div id="divMessages" style="color:#f00"></div>
 
 <div id="renderDepartment"></div>

Add Script file GetData.js to Script folder and refer it in ReceiverAppPart.aspx

 'use strict';
 
 var departmentId;
 
 var hostweburl;
 
 var appweburl;
 
 var allDepartmentId;
 
 // This code runs when the DOM is ready and creates a context object which is needed to use the SharePoint object model
 
 $(document).ready(function () {
 
 window.addEventListener("message", receiveMessageInApp, false);
 
 function receiveMessageInApp(event) {
   
   var divMsg = document.getElementById('divMessages');
   
   departmentId = event.data;
   
   //Get the URI decoded URLs.
   
   hostweburl =
 	
 	decodeURIComponent(
 	  
 	  getQueryStringParameter("SPHostUrl")
 	  
 	);
   
   appweburl =
 	
 	decodeURIComponent(
 	  
 	  getQueryStringParameter("SPAppWebUrl")
 	  
 	);
   
   // resources are in URLs in the form:
   
   // web_url/_layouts/15/resource
   
   var scriptbase = hostweburl + "/_layouts/15/";
   
   // Load the js files and continue to the successHandler
   
   $.getScript(scriptbase + "SP.Runtime.js",
 			  
 			  function () {
 				
 				$.getScript(scriptbase + "SP.js",
 							
 							function () {
 							  $.getScript(scriptbase + "SP.RequestExecutor.js", execCrossDomainRequest);
 							}
 							
 						   );
 				
 			  }
 			  
 			 );
   
 }
 
 }
 			   );
 
 // This function prepares, loads, and then executes a SharePoint query to get the current users information
 
 // Function to prepare and issue the request to get
 
 //  SharePoint data
 
 function execCrossDomainRequest() {
 
 // context: The ClientContext object provides access to
 
 //      the web and lists objects.
 
 // factory: Initialize the factory object with the
 
 //      app web URL.
 
 var context = new SP.ClientContext(appweburl);
 
 var factory =
 	
 	new SP.ProxyWebRequestExecutorFactory(
 	  
 	  appweburl
 	  
 	);
 
 context.set_webRequestExecutorFactory(factory);
 
 //Get the web and list objects
 
 //  and prepare the query
 
 var web = context.get_web();
 
 var list = web.get_lists().getByTitle("DepartmentData");
 
 var camlString ="<View>" +
 "<Query>" +
 "<Where><Eq><FieldRef Name='Title' /><Value Type='Text'>" + departmentId + "</Value></Eq></Where>" +
 "</Query>" +
 "<ViewFields>" +
 "<FieldRef Name='Title' />" +
 "<FieldRef Name='DepartmentName' />" +
 "</ViewFields>" +
 "</View>";
 								
 var camlQuery = new SP.CamlQuery();
 
 camlQuery.set_viewXml(camlString);
 
 allDepartmentId = list.getItems(camlQuery);
 
 context.load(allDepartmentId, "Include(Title , DepartmentName)");
 
 //Execute the query with all the previous
 
 //  options and parameters
 
 context.executeQueryAsync(
   
   successHandler, errorHandler
   
 );
 
 }
 
 // Function to handle the success event.
 
 // Prints the data to the page.
 
 function successHandler(data, req) {
 
 var enumerator = allDepartmentId.getEnumerator();
 
 while (enumerator.moveNext()) {
   
   var department = enumerator.get_current();
   
   var departmentTitle = department.get_item("Title");
   
   var departmentDescription = department.get_item("DepartmentName");
   
   divMessages.innerHTML = departmentDescription;
   
 }
 
 }
 
 // Function to handle the error event.
 
 // Prints the error message to the page.
 
 function errorHandler(data, error, errorMessage) {
 
 document.getElementById("renderDepartment").innerText =
   
   "Could not complete cross-domain call: " +
   
   errorMessage;
 
 }
 
 // Function to retrieve a query string value.
 
 // For production purposes you may want to use
 
 //  a library to handle the query string.
 
 function getQueryStringParameter(paramToRetrieve) {
 
 var params =
 	
 	document.URL.split("?")[1].split("&");
 
 var strParams = "";
 
 for (var i = 0; i 
 	 < params.length; i = i + 1) {
   
   var singleParam = params[i].split("=");
   
   if (singleParam[0] == paramToRetrieve)
 	
 	return singleParam[1];
   
 }
 
 }

Deploy both the Apps and browse you share point Team site.

Create one new site page i.e. CreateConnection.aspx and browse and edit the page. Click on Add Web Part and select Script Editor Web Part

Add Script Editor WebPart

 <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>

Add AppPart i.e. Sender AppPart Title and Receiver AppPart Title.

Click on Stop editing with happy ending!!

Author Info

Manoj Kumar Mittal
 
SharePoint Developer
 
Rate this article
 
Manoj Mittal has been working in IT Industry for over 8+ years. He holds a Masters Degree (MCA). He is passionate about learning and sharing the tricks and tips and ...read more
 

Leave a comment