[UPDATE 09/12/2016]
This approach was quickly superseded by an integrated rendering framework which I will blog about ASAP.
Overview
One of the limitations of the app model and the use of app parts is that iframes are used to render content. There are workarounds to blend the look and feel into the SharePoint site (host web css, postmessage resize, etc.) but ultimately having a JavaScript model that runs inside the same page is a much more practical approach, especially when trying to create a responsive design. When developing a product-based app part, the limitations imposed by the iframe approach make sense security-wise but when you are create a company intranet using the app model approach, this iframe approach becomes an unnecessary limitation.
The app part communication framework has been created to overcome the restrictions that the use of iframes in app parts imposes and makes use of the benefits of having control over the master page when developing in SharePoint Online for a company intranet.
Its current state is the result of a couple weeks of on and off contemplation and a few hours of development - thus it is still in its early stages and is going to be expanded upon (and used in a production environment) and so I will revisit this post and update it accordingly.
The latest SharePoint announcements regarding upcoming changes later this year/next year should overcome the issue I am trying to solve here, so the timing of this is rather ironic, but I still feel that this framework is worth posting about, not least because I can point the development and support team to it.
Updated
2016-05-10: Added support for auto-loading app part JavaScript
2016-05-11: Added to codeplex.
Background
As solution architect on a new project (and solution architect on the previous project with the same customer) I am trying to find a way to create a practical coding approach to using app parts in a responsive design-based content management system. Our previous portal (not responsive design) implementation contained numerous heavy-handed farm solution-based customisations and all of these need to be part of the new template-based portal which must ideally fit within the app model so that if/when we move to SharePoint Online, there is minimal effort required. Thus my intent is to completely avoid the use of farm solutions.
The new project is aimed at providing responsive design-based reusable SharePoint site template(s) that can offer the same easy-to-use web parts (tiles, carousels, custom media, etc.) that are in the existing portal - but of course, these need to be app parts. In creating these parts, our UI designer is currently creating these inline rather than in app parts and so I really wanted to provide a way to have the flexibility of an editor choosing to add parts to the page while editing but have the rendering happen in the main page, outside the iframe. This meant that there would need to be a way for the app part's iframe to communicate about the app part to the main page and allow the main page to do the rendering.
There is already a script used by the SP app part framework for communicating back and forth and it makes use of the rather brilliant postMessage method. This method can be called from an iframe which in turn triggers an event in the parent page. In the parent page you can choose to receive these messages by registering to handle the onmessage event from which you will receive the data sent by the iframe. The same works in reverse too - the parent window can send messages to the iframe via the postMessage method. All of this means that if we have control of the master page then we can create a framework for the app parts "chatting" to the master page (or one another if desired - though that is not the intent of this framework, it would take only small modifications to allow that to happen). By creating a framework for this "chatting" to occur, we can build a client-side JavaScript-based framework for rendering app parts in the context of the SharePoint page instead of the iframe and that will allow our responsive design framework to easily control the rendered nodes.
Solution
Firstly, this is in the very early stages of development but please feel free to suggest any changes/improvements in the approach taken or any of the coding methodology.
I will add diagrams at a later point but for now I am writing this up quickly so it can be used by the team.
The basic structure is this:
- Files
- APCF.js - resides in provider hosted website
- APCF[app part type].js e.g. APCFAppPartExample1.js - resides in the provider hosted website
- Provider-hosted app part - contains inline script that calls postMessage
- JS Objects
- The APCF object is an object initialised using literal notation and comprises a few methods for processing message and registration of app parts
- The APCFAppPartType object is used to describe an object type identifier - each app part registers itself as an app part type
- The APCFAppPartInstance is a base object from which each type of app part inherits a class (using the 'apply' method). Each of these inheriting instance classes are the identified in the APCFAppPartType object
- This base object has a flow of execution upon registration: initialise, load, render
- Each of these is declared in the base object as a "_base" so initialise_base, load_base, render_base - and each of these methods first calls the respective methods (initialise, load, render) then calls the next base method
- This means that if an instance implements the initialise, load or render methods then they will be called in that order automatically
The basic flow is this:
- Main page loads jQuery
- Main page loads the APCF.js file which comprises:
- APCF declaration
- APCFAppType declaration
- APCFAppInstance declaration
- Registers onmessage event to call APCF.processMessage
- Each app part aspx loads jQuery and APCF.js and the relevant App Part Type JS file and register the APCF.processMessage to handle APCF events
- On load, app part uses postMessage to send a serialized object (currently manually created but should be wrapped)
- postMessage is picked up by APCF.processMessage running within the main page, deserializes the object and checks the messageType property
- A switch statement calls the relevant APCF method depending on the messageType
- The first call from the app part registers the App Type which contains the App Part Type registration information (including script URL)
- This causes the APCF to call the iframe back using postMessage to say the app type has been registered
- On handling the registration, the app part ASPX then registers the instance
- Registratioin of the instance causes the APCF to start rendering
The code is available from the URL above. Please feel free to comment. I will add documentation to the codeplex site ASAP