Question

Alfontz on Wed, 20 Mar 2019 13:31:49


Thanks for any asssistance.

I have several provider hosted SharePoint Add-ins with custom actions on the CommandUI.Ribbon for document libraries that interact with the list and selected items.  I get the values from the Command Handlers URL (SelectedListId, ListId, SelectedItemId)

Issue is the SelectedListId, ListId & ListUrlDir values in the CommandUIHandler::CommandAction are the 'Site Pages' list when invoked from a webpart on a Modern page.  So a custom action invoked from a Modern page fails.

Since the Custom Action is associated with 'Document Library' and not the 'Site Pages' list, I would expect the values in the CommandAction would represent the 'Document Library' values.  Similar to how it works on the Document Lib's view pages.

From the Modern page web part toolbar:
SelectedListId = 'Site Pages' list ID
ListId = 'Site Pages' list ID
ListUrlDir = 'Site Pages' URL
SelectedItemId = The selected item from the list shown by the webpart (document library)

From the List's (Document Library) view page, classic Ribbon or Modern toolbar:

SelectedListId = The 'Document Library' list ID
ListId = The 'Document Library' list ID
ListUrlDir = The 'Document Library' list URL
SelectedItemId = The selected item from the list

Regards,

Al



Al

Replies

Jerry Zy on Thu, 21 Mar 2019 06:30:21


Hi,

Url Tokens will both work for Site Pages and library, this is just a expression which stand for some url in SharePoint:

'{SelectedListId}' - ID (GUID) of the list that is currently selected from a list view.

'{ListId}' - ID (GUID) of the list (ID).

'{ListUrlDir}' - Server-relative URL of the site plus the list's folder.

'{SelectedItemId}' - ID of the item that is currently selected from the list view.

And here is a demo which used Url Token {ListId} in CommandUIHandler:

    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
      <CustomAction
       Id="EmailContacts"
       RegistrationType="List"
       RegistrationId="105"
       Location="CommandUI.Ribbon">
        <CommandUIExtension>
          <CommandUIDefinitions>
            <CommandUIDefinition
             Location="Ribbon.ListItem.Actions.Controls._children">
              <Button
                Id="Ribbon.ListItem.Actions.Email"
                Alt="$Resources:core,E-Mail;"
                Sequence="55"
                Command="emailContacts"
                LabelText="$Resources:core,E-Mail;"
                Description="$Resources:core,E-Mail;"
                TemplateAlias="o1"/>
            </CommandUIDefinition>
          </CommandUIDefinitions>
          <CommandUIHandlers>
            <CommandUIHandler
             Command="emailContacts"
             CommandAction="javascript:
               function getItemIds()
               {
                 var itemIds = '';
                 var items = SP.ListOperation.Selection.getSelectedItems();
                 var item;
                 for(var i in items)
                 {
                   item = items[i];
                   if(itemIds != '')
                   {
                     itemIds = itemIds + ',';
                   }
                   itemIds = itemIds + item.id;
                 }
                 return itemIds;
               }
               function handleReadyStateChange()
               {
                 if (client.readyState == 4)
                 {
                   if (client.status == 200) 
                   {
                     // client.responseText is mailto string
                     window.location = ('mailto:' + client.responseText);
                   }
                 }
               }
               function invokeEmailContacts()
               {
                 var params = 'itemids=' + getItemIds(); 
                 // Posting to EmailContacts.ashx to get the mailto string
                 var site='{SiteUrl}'; 
                 var url = site + '/_layouts/emailcontacts.ashx?listId={ListId}';
                 client = null;
                 client = new XMLHttpRequest();
                 client.onreadystatechange =  handleReadyStateChange;
                 client.open('POST', url, true);         
                 client.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
                 client.setRequestHeader('Content-length', params.length);
                 client.send(params);
               }      
               invokeEmailContacts();"
             
          EnabledScript="javascript:
               function enableEmailContacts()
               {
                 var items = SP.ListOperation.Selection.getSelectedItems();
                 return (items.length > 0);
               }
               enableEmailContacts();"/>
          </CommandUIHandlers>
        </CommandUIExtension>
      </CustomAction>
    </Elements>

Reference:

CommandUIHandler element

Thanks

Best Regards

Alfontz on Thu, 21 Mar 2019 15:07:32


Hi Jerry,

Thanks for the reply.  I've seen and use this article.  However 2 issues with it.

#1 Sample fails.  Steps to recreate:

  1. In VS 2017 create a SharePoint add-in project (SharePoint or Provider hosted) and target SharePoint Online.
  2. Add 'New Item' select "Ribbon Custom Action".
  3. In the wizard select: "Host Web", "List Template", "Contacts"
  4. Replace Elements.xml contents with the sample xml.
  5. Build & Run
  6. Note Error in Output:  Error occurred in deployment step 'Install SharePoint Add-in': There were errors when validating the App Package.

Custom Actions cannot contain javascript.  See: https://docs.microsoft.com/en-us/sharepoint/dev/sp-add-ins/sharepoint-add-ins-ux-design-guidelines

#2 Original issue, when the command is invoked from a web part on a Modern page the values for '{ListId}' & '{SelectedListId}' are the 'Site Pages' list not a Contact list (RegistrationId="105") or Document lib (RegistrationId="101").  Steps to recreate:

  1. Create a SharePoint add-in, target SharePoint online.
  2. Add a Ribbon Custom Action and register to Document Library
  3. Run and deploy to a SharePoint site with a Document Library with files.
  4. On the SharePoint site open Site Pages and add a new page.  This will be a Modern page.
  5. On the page give a title, Add a "Document Library" web part and select your library.
  6. Publish the page.  Notice the Custom action is available on the web part.
  7. Click the Custom Action button to Invoke.  Note that the SelectedListId & ListId = Site Pages list Id, Not a Document Library list Id.
  8. Navigate to the document library view page and invoke the Custom action there.  Note the SelectedListId & ListId = are the id to the Document Library.

Here is my test Add-in project.  The command has a page displaying the token values. https://github.com/allenj3304/Testing/tree/master/MySharePointApp

This behavior is confusing since the CustomAction.RegistrationId=101 a Document Library not a Page Library (119)

Is this a Bug or intended behavior?  If intended then how can developers remove the custom action from the Webpart?

Thanks,

Al

Jerry Zy on Fri, 22 Mar 2019 09:12:07


Hi,

The Command action example in Provider Hosted add-in  is used in the classic UI library and if want to achieve the custom Ribbon Action for Modern UI library and list, please use PnP Provision xml and apply with PnP Provision Engine:

Customizing "modern" lists and libraries 

Apply the Provisioning Xml with PnP PowerShell:

Introducing the PnP provisioning engine

Thanks

Best Regards

Alfontz on Fri, 22 Mar 2019 18:31:24


Hi,

Thanks.  I've seen this.  However in my and my customers SharePoint online with our Add-ins installed, the Custom action group with buttons show up in the web parts on modern pages.  Thus they don't work due to the wrong SelectedListId & ListId.

Thanks for the help.  I'm escalating this and submitting a support incident through MPN.

Al

Jerry Zy on Mon, 25 Mar 2019 05:48:00


Hi Alfontz,

If have any updates, please share the information with us so that it could also help others who stuck with the same question in the forum.

Thanks

Best Regards