Thursday, April 17, 2014

Custom Actions in Apps for SharePoint 2013

Introduction

Custom actions in Apps for SharePoint allow users to interact with list menu and SharePoint ribbon. You can deploy custom actions either to host web or app web. Deploying to app web will restrict the custom action just within your app. When a custom action is deployed to the host web, you can allow users to open a page in your app – in this way it is very easy to allow users navigate to your app.
For example: If you have an event management app that picks the events from the event calendar in the host web, then you could have a list menu custom action that allows users to register for the selected event by taking you directly to the event management app.
Custom actions can be either:
  • List Menu Custom Action
  • Ribbon Custom Action
In this blog post let us lets create a simple list menu custom action using Visual Studio 2012!

List Menu Custom Action Sample

Creating the List Menu Custom Action

Open Visual Studio 2012 as administrator (this is required to build apps for SharePoint)
Create a new project and select App for SharePoint 2013
Enter MyCustomAction for the project name
In the next wizard page, enter your SharePoint site Url and select SharePoint-hosted as your hosting option
Click Finish to create the project
image
Right click the app for SharePoint project and select Add | New Item
Choose Menu Item Custom Action and enter MyListMenuCA as the Name
image
Click Add to add the custom action
In the next wizard page, you can choose where to deploy your custom action along with the scope of the custom action
Choose Host Web and scope the custom action to List Instance
Choose Documents library item for which the custom action is scoped to
image
Notice that you can choose various locations where you want to scope your list menu custom action
 image
If you had chosen File Extensions, you are able to then choose the file extension type (though only 3) – pretty cool :)
image
Back to the wizard – click Next to proceed
In the next wizard page, you can choose the appropriate name for the menu item and the page (in the app) to navigate to.
Accept the defaults and click Finish to create the custom action
image
Visual Studio will add the custom action to your project
image
Press F5 to debug your app and if everything works, then you will be taken to the app directly:
image
Since our custom action is deployed to the Documents library in the host web, we have to navigate to that library to invoke the custom action
Click on the Developer Site on the top left corner – this will take you to the host web.
Navigate to Documents library and select any document in the library and click the ellipsis icon to show the list menu
Click the ellipsis icon again (yep, too many ellipsis! :) ) and there you will find your custom action at the end!
 image
Clicking on the custom action should take you the app

Writing code to get item details

What is the use of the custom if we are not able to get the details of the item from which it was invoked, right?
Let us write some code to exactly do that!

Include Query String Parameters

In order to get the item details, we need SharePoint to pass some values as query string parameters
Open Elements.xml under the custom action MyListMenuCA
We will replace the UrlAction element’s Url property to include the following:
  • Standard tokens
  • Query string parameters for:
    • List Id
    • List Item Id
Below is the modified code:
<UrlAction Url="~appWebUrl/Pages/Default.aspx?{StandardTokens}&amp;SPListItemId={ItemId}&amp;SPListId={ListId}" />
The code corresponding to the query string parameter is:
{StandardTokens}&amp;SPListItemId={ItemId}&amp;SPListId={ListId}

Display Query String Parameters

Lets replace the Default.aspx PlaceHolderMain content place holder with the following code:
<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">

    <div>
        <ul id="queryStringParams" />
    </div>

    <div>
        <input type="button" id="btnItemDetails" 
            onclick="getItemDetails()" value="Get Item Details" />
    </div>  

    <div>
        <p id="message">            
            No item selected.
        </p>
    </div>

</asp:Content>
Open App.js in the Scripts folder:
Add the following variables at the top:
var appWebContext;
var hostWebContext;

var web;
var hostWeb;

var selList;
var selListItem;
Replace the document.ready function with the following:
$(document).ready(function () {

    var params = $.getUrlVars();

    if (!$.getUrlVar("SPListItemId")) {
        $("#btnItemDetails").prop("disabled", true);
    }

    var paramsHTML = "";   

    for (var i = 0; i < params.length; i = i + 1) {
        params[i] = decodeURIComponent(params[i]);
        paramsHTML += "<li>" + params[i] + " ==> "
            + decodeURIComponent($.getUrlVar(params[i])) + "</li>";
    }

    document.getElementById("queryStringParams").innerHTML = paramsHTML;

});
The code above gets the query string parameters and builds a string inserts that text into the Html element queryStringParams
Now add the code query the query string(thanks to jQuery Howto blog for the code):
$.extend({
    getUrlVars: function () {
        var vars = [], hash;
        var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
        for (var i = 0; i < hashes.length; i++) {
            hash = hashes[i].split('=');
            vars.push(hash[0]);
            vars[hash[0]] = hash[1];
        }
        return vars;
    },
    getUrlVar: function (name) {
        return $.getUrlVars()[name];
    }
});
If you debug the app now, you will see the query strings passed:
image

Get Item Details

Let us now implement the Get Item Details method to query the selected item
Remember, custom action is deployed to host web and the selected item is actually in a document library in the host web
So, we have to query the host web document library to get the item details
function getItemDetails() {

    appWebContext = new SP.ClientContext.get_current();

    hostWebContext = new SP.AppContextSite(appWebContext, decodeURIComponent($.getUrlVar("SPHostUrl")));

    selList = hostWebContext.get_web().get_lists().getById(decodeURIComponent($.getUrlVar("SPListId")));

    selListItem = selList.getItemById(decodeURIComponent($.getUrlVar("SPListItemId")));

    appWebContext.load(selList);

    appWebContext.load(selListItem, 'Title');

    appWebContext.executeQueryAsync(onGetListItemSucceeded, onFail);
}

function onGetListItemSucceeded(sender, args) {

    $("#message").text("Selected Item Title = " + selListItem.get_item('Title'));
}
function onFail(sender, args) {
    alert('Failed to execute the request. Error:' + args.get_message());
}
How do we query the host web? – the code in Red shows how to query the host web – get the current context (app) and we will create a new app context for the host web by passing the site Url, which is the SPHostUrl in the query string. Once we have the host web context, we can then get the associated list by list Id and then the item by Id. But you still have to execute the original appWebContext as your code is executed within your app.
Lets see what we get if we debug the app, invoke the custom action and press Get Item Details button:
image
Oops! – That is not good – what is wrong?
As the item is in a library in the host web, the app has to have the required permissions to access the specified library to query the item!

Configure App Permissions

We haven’t configured any permissions yet.
Open AppManifest.xml and navigate to Permissions tab
Add the following permission to read a list:
image
We have requested permission to read a list but we haven’t specified which list. The list will be requested during the installation.
Lets debug the app:
You are now requested to choose from which list you want the app to have read permission
Select Documents as we have deployed our custom action to the Documents library and click Trust It
image
Now invoke the custom action and press Get Item Details button:
You should see the item title being updated below the button
image


No comments:

Post a Comment