Monday, August 15, 2016

SharePoint Online Tasks list Custom Action

I was trying to add a custom action to my Custom list using Visual Studio 2013 and was pretty straight forward. But when I tried to do the same with Tasks list my custom ribbon action button never showed up. For custom tasks list it is little different compared to custom list template. Here is how you can add a Custom button for Tasks list:

1. Create Custom Tasks list using Tasks list template in SharePoint online. My list name here is "My Tasks"
2. Open VS 2013
3. Create a SharePoint hosted app and add a custom Ribbon action.
4 Below are the changes made in Elements.xml to make it to work

Replace CommandUIDefinition Location value with "Ribbon.Tasks.New.Controls._children"
and for Button Id value with "Ribbon.Tasks.New.RibbonCustomAction4Button"

In the example below I have custom ribbon action added to my "My Tasks" list.

This is how my Emelemts.xml looks like-

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="a3957d8c-dee7-4a6c-9d32-6e1531da84f5.GetReport"
                RegistrationType="List"
                RegistrationId="{$ListId:Lists/My Tasks;}"
                Location="CommandUI.Ribbon"
                Sequence="10001"
                Title="Invoke &apos;GetReport&apos; action" >
    <CommandUIExtension>
      <!--
      Update the UI definitions below with the controls and the command actions
      that you want to enable for the custom action.
      -->
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.Tasks.New.Controls._children">
          <Button Id="Ribbon.Tasks.New.RibbonCustomAction4Button"
                  Alt="Request GetReport"
                  Sequence="100"
                  Command="Invoke_GetReportButtonRequest"
                  LabelText="GetReport"
                  TemplateAlias="o1"
                  Image32by32="_layouts/15/images/placeholder32x32.png"
                  Image16by16="_layouts/15/images/placeholder16x16.png" />
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="Invoke_GetReportButtonRequest"
                          CommandAction="~appWebUrl/Pages/Default.aspx?{StandardTokens}&amp;SPListItemId={SelectedItemId}&amp;SPListId={SelectedListId}"/>
      </CommandUIHandlers>
    </CommandUIExtension >
  </CustomAction>
</Elements>

Deploy your app and see if the custom button "GetReport" shows up in the ribbon for "My Tasks" list.

Saturday, August 6, 2016

SharePoint Online Announcements or News App Part

One of my requirements was to display all Announcements from my hosted SharePoint site in a Client Web Part.

To keep it simple for this post I have an Announcements list in my SharePoint Online site. This list contains Title, Body, Expiration Date columns. I have to display all announcements from the list in my Client Web Part. Also. I have a custom property where the list name is configured and use that as my parameter to read all list items.

For now I will go with simple CSS and JS. You can customize the CSS as needed as per your branding requirements.

I am using Visual studio 2013 for my project here. Start from creating a SharePoint Hosted App and type some name like AnnouncementsAppPart. Add a new Client Web Part (Hosted Web) and lets give same name AnnouncementsAppPart.

When we added a client web part it adds AnnoucenmentAppPArt with Elements.xml file and AnnoucenmentAppPArt.aspx  page under Pages.

This is how my project file structure looks like:



Before getting into App Part code or rather I should before I forget, I prefer to set the permissions of my app part. So that I know this app has access to Read SharePoint Announcements list.

If you notice you will have a AppManifest.xml, which is where I will configure permissions of my hosted app. Since I want to Read and display Announcements items from my hosted App, at a minimum I have to give Read access.


This will give my app permissions to read list items from a list.

Now going back to the AnnouncementsAppPart, if you notice this added a Elements.xml file just below the AnnouncementApp Part. This is file where we can configure Announcements Client Web Part custom Web part Properties, Title, Description, default height and Width.

Instead of hard coding Announcements list name in my App, I am adding a custom property to get the list name and display the list items. This is how we can add a custom property-

 <Properties>
           <Property Name="ListName" Type="string" WebBrowsable="true" WebDisplayName="Announcement ListName" WebDescription="Announcement ListName" WebCategory="App Settings" DefaultValue="Announcements" RequiresDesignerPermission="true" />
    </Properties>

If needed I can also add default list name "Announcements", since I already know the list name.

Now the question is how can I get my custom property "ListName" value in my code to read the list items. So here is how we can-


In the Content tag above I give my AnnoucenmentAppPArt  Page name, which was created under Pages folder and if you notice after {StandardTokens} I am passing my custom parameter name like -

&amp;ListName=_ListName_

Basically with this code line above I am trying to pass my ListName as a query string parameter after & in the host web url to grab it in my code later and display the list items.

Now starts the fun part. First I thought I can just create a client context "context " to read SharePoint list and display items. But I was wrong, I was not able to access my Announcements list with this object.

After googling and trying to figure out what was I missing, I came through Corey Roth's article, and that saved my day. After creating a new context from SP.AppContextSite I was able get my list object and then retrieve all the list items.

I created a custom Announcements.js file and here is the code looks like.

'use strict';

var context = SP.ClientContext.get_current();
var parentContext;
var web;
var collListItem;
// 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 () {
    getAnnouncements();
});

// This function prepares, loads, and then executes a SharePoint query to get the current users information
function getAnnouncements() {


    //display announcements
    $('#lblResultLists').text("Corporate Announcements:");

  var  hostwebUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
  var  appwebUrl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));

    parentContext = new SP.AppContextSite(context, hostwebUrl);

    var listName = decodeURIComponent(getQueryStringParameter("ListName"));
    if (listName == "undefined")
        listName = 'Announcements';

    web = parentContext.get_web();

   // alert(context.get_web().get_url());
    var oList = web.get_lists().getByTitle(listName);

    //get items
    var camlQuery = new SP.CamlQuery();
    camlQuery.set_viewXml('<View><Query><FieldRef Name=\'Title\'/>' +
        '<FieldRef Name=\'Body\'/></Query></View>');
     collListItem = oList.getItems(camlQuery);

    context.load(collListItem);
    context.executeQueryAsync(onGetAnnouncementSuccess, onGetAnnouncementFail);
}

// This function is executed if the above call is successful
// It replaces the contents of the 'message' element with the user name
function onGetAnnouncementSuccess() {

    var listItemInfo = '';

    var listItemEnumerator = collListItem.getEnumerator();

    while (listItemEnumerator.moveNext()) {
        var oListItem = listItemEnumerator.get_current();
        
        listItemInfo += "<table cellpadding='0' cellspacing='0' width='100%'><tr><td class='S2StyleTitle' colspan='2'> <a id='OpenDialog' class='announcementPopUp' href='#' >";
        listItemInfo += oListItem.get_item('Title');
        listItemInfo += "</a></td></tr><tr><td class='announcementdescription' valign='top' >";
        listItemInfo += oListItem.get_item('Body');
        listItemInfo += "</td></tr></table>";
    }

    $("#grid").html(listItemInfo);

}

// This function is executed if the above call fails
function onGetAnnouncementFail(sender, args) {
    alert('Failed to display Announcements. Error:' + args.get_message());
}
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];
    }

}

Now the next step is to point all my custom css and js files form AnnouncementsAppPart.aspx page



Now the last step is to select AnnouncementsAppPart.aspx in AppManifest.xml file and save it.



That's it, hope this helps. Save it and deploy to your developer site. When you are ready with your custom CSS changes add this client web part as App Part to App catalog and you can add this as App Part in any other SharePoint Online sites.

Attached is the source code.
sourcecode