Use the SharePoint hidden list to store configuration data for an app part instance
In this article, we explain a method to store configuration data by using a SharePoint hidden list. We also explore an alternative scenario that might be useful under certain circumstances.
When developing an app for SharePoint, we found that using a SharePoint hidden list in the app web is a good approach for most scenarios. We also evaluate another approach using custom properties that may fit some scenarios under particular circumstances.
What is an app part?
An app part (AppPart) is an embedded part for a SharePoint website. It is one type of WebPart represented by the ClientWebPart class. With an app part, you can install and show your apps for SharePoint right in a page inside the SharePoint hosting website. Users can add multiple app parts to a single SharePoint hosting website. And sometimes, they want to customize each app part instance’s appearance and behavior.
For how to create an app with an app part, and add some properties to it, see How to: Create app parts to install with your app for SharePoint.
How do you store the various configuration data so that the hosting SharePoint website and the app part can interact with each other? In this article, we discuss two approaches, the recommended approach using a hidden list and an alternative approach using custom properties.
Use SharePoint hidden list to store configuration data
We recommend to use the SharePoint hidden list to store data for each app part instance. The SharePoint hidden list is built within the app’s hosting web when the app is installed on a SharePoint site.
First you get the current WebPart ID by adding tokens in the URL, and then you store data related to the current app part to one record of the hidden list when the app part is added.
Add tokens to URL
The following code is in element.xml file. Attribute Src points to the app hosting page to be rendered in an app part. The code includes several tokens. Here WpId stands for the WebPart ID of the current app part.
<Content
Type="html"
Src="~appWebUrl/Pages/SampleAppPart.aspx?{StandardTokens}
&wpId=_WPID_" />
After these tokens are added, when the SampleAppPart.aspx file loads, the property values can be extracted from the query string using the following JavaScript scripts.
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
if (param[0] == "wpId") {
webpartId = decodeURIComponent(param[1]);
webpartId = webpartId.replace("g_", "").split("_").join('-');
}
}
How to use the SharePoint hidden list to store configuration date?
- Create a list within the current project.
- Right click the current project, choose Add > New Item. The Add New Item – Sample windows appears as in Figure 1
Figure 1. Add a list in your app web - Name the list ConfigList, and click Add.
- Choose the default custom list and click Finish. This list will be created once the app is installed on the SharePoint site, and it will be deleted after the app is uninstalled.
Figure 2. Create a list
- Right click the current project, choose Add > New Item. The Add New Item – Sample windows appears as in Figure 1
- Create columns and each column represents one configuration data.
In the Solution Explorer, double click “ConfigListInstance” under ConfigList.
Edit the columns for this list.
Here we create two columns of strings named “WebPartId” and “Name” respectively, and a numeric type column named “Id” as shown in Figure 3. And you can customize your configuration columns according to your own specific requirements.
- Add the "wpId=_WPID_" to src as a parameter through the way we used in the previous subsection and to parse out the WebPart Id with JavaScript.
- Next, we would write code and realize this: once the app part is loaded, we detect whether the current web part has its record in ConfigList by WebPart ID. If not, we will add one; otherwise, we will retrieve all the configuration data and use the data to render pages.
Figure 3. Customize your list columns
Note that in this approach, when a user removes an app part, no event can be detected within the app’s hosting page. Hence the corresponding record cannot be removed, which could be a risk for scenarios with big configuration data and app part frequent deletion.
How to use app part’s custom properties to store configuration data?
An app part is essentially a wrapper for an IFrame that hosts a page within the app’s hosting website. If the page rendered within an app part wants to visit the app part’s properties, it needs the app part’s hosting website’s URL and the hosting page’s URL. With these two URLs, all the web parts on the app part hosting website can be retrieved. And then we can filter them using WebPart ID. Finally, we can store configuration data in the app part.
Because this app is trying to query the WebParts in the page, this approach needs the app the list scope manage permission of the hosting SharePoint website page. You get this by updating the manifest file AppManifest.xml.
If you already know the app part hosting website’s URL and the hosting page’s URL, you can use the AppPart’s custom properties to store all configuration data. This approach has two advantages.
- Data is stored in an AppPart, and data will be deleted once the AppPart is deleted.
- The implementation and maintenance is easy.
However, the AppPart custom properties approach only works when certain conditions are met.
Conditions
Using the AppPart custom properties to store data required the following conditions to be true:
- Developers need to know ahead of time the app part’s hosting website’s URL and the hosting page’s URL. Note that the response Referrer property doesn’t always work well.
- Your app must have the list manage permission. Granting an app the list manage permission inside the hosting SharePoint site is not a good practice because the app might therefore access all app parts from other apps inside that hosting website. This is contrary to the SharePoint apps’ philosophy of being self-contained.
- Your app part must be hosted in a WebPart page. Implementation related to API oWebPartDefinition.get_id() only works on WebPart pages. It doesn’t work on Wiki pages.
Due to these requirements, we don’t recommend you to use app part’s custom properties to store data. In the following subsection, we talk briefly the process of this approach for demo purpose.
Assign appropriate list scope permission to the app
Open the file AppManifest.xml in Visual Studio 2012, click the Permissions tab and then add the Manage permission to the list scope.
Figure 4. Assign the list scope manage permission to your app
Define an app part’s custom properties
In one app part, custom properties can be defined in the app part’s element.xml file. Each property can be given attributes such as name, type, and default value.
In the element.xml file, add two custom properties named strProp and intProp to the attribute Src.
<Content
Type="html"
Src="~appWebUrl/Pages/SampleAppPart.aspx?{StandardTokens}
&strProp=_strProp_&intProp=_intProp_&wpId=_WPID_" />
<Properties>
<Property
Name="strProp"
Type="string"
RequiresDesignerPermission="true"
DefaultValue="String default value"
WebCategory="Basic app part category"
WebDisplayName="A property of type string.">
</Property>
<Property
Name="intProp"
Type="int"
RequiresDesignerPermission="true"
DefaultValue="0"
WebCategory="Basic app part category"
WebDisplayName="A property of type integer.">
</Property>
</Properties>
After these tokens are added, when the SampleAppPart.aspx file loads, the property values can be extracted from the query string using the following JavaScript scripts.
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
if (param[0] == "wpId") {
webpartId = decodeURIComponent(param[1]);
webpartId = webpartId.replace("g_", "").split("_").join('-');
} else if (param[0] == "strProp")
strProp = decodeURIComponent(param[1]);
else if (param[0] == "intProp") {
intProp = decodeURIComponent(param[1]);
}
}
To get or set custom properties, we need specify the app part’s hosting website’s URL (siteUrl) and the hosting page’s URL (serverRelativeUrl). Otherwise, this implementation does not work.
var siteUrl = "/sites/test";
var serverRelativeUrl = "/sites/test/SitePages/sample.aspx";
We could get all the web parts on this hosting website by limitedWebPartManager.get_webParts(), find the current app part using WebPartId, and get all properties of an app part by get_properties(). And then we update the custom properties by set_item ('strProp', 'My String Prop value').
As mentioned above, this approach can only work under certain circumstances and we recommend the SharePoint hidden list approach mentioned in the previous section.
References
Attribution
This article was written by ecoSystem team SDE Peng Wang, content publishers Ricardo Loo Foronda and Tony Liu. Program managers Humberto Lezama Guadarrama and Sudheer Maremanda provided valuable feedback.
Comments
Anonymous
October 20, 2013
Thanks for this post, it is informative but has one big gap. When using your first method in Office 365, you cannot get the URL of the page that hosts the App Part to store it in your "hidden list". The reason for this is that in Office 365 your iframe source is pointing to silentSignIn.aspx (which redirects you), but then document.referrer is no good to you, so you cannot get the web part properties. You've pointed out that referrer doesn't work well, but clients need a solution to this problem as it is a serious limitation.Anonymous
November 06, 2013
Hi, It is good to know that custom properties can be retrieved and modified from JSOM. Even if it is under these conditions. However if I try this, I keep getting the following error message from MicrosoftAjax.js: Unable to get property 'apply' of undefined or null reference This is my code. var siteUrl = '/'; var serverRelativeUrl = '/SitePages/Default.aspx'; var clientContext = new SP.ClientContext(siteUrl); var file = clientContext.get_web().getFileByServerRelativeUrl(serverRelativeUrl); var limitedWebPartManager = file.getLimitedWebPartManager(SP.WebParts.PersonalizationScope.shared); var webparts = limitedWebPartManager.get_webParts(); clientContext.load(webparts); clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed)); I get the error message just after executing executeQueryAsync, so I never get into either the succeeded or failed method. Do you have any idea what may be the cause of this? Any help would be greatly appreciated! EdAnonymous
November 12, 2013
The comment has been removed