Solved

Custom Ribbon Action - Disabled with Document Set Selection

Posted on 2014-04-06
13
750 Views
Last Modified: 2014-07-20
The custom action enables/disables when a list item or folder is selected/deselected. The issue I'm running into is when a document set is selected, the custom action remains disabled.


Custom Ribbon Action:
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction
      Id="LinkDocsCustom"
      Location="CommandUI.Ribbon"
      RegistrationType="ContentType"
      RegistrationId="0x01">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.Documents.Groups._children">
          <Group
              Id="LinkDocsCustomGroup"
              Sequence="15"
              Description="Copy permanent link to clipboard"
              Title="Permanent Link"
              Template="LinkDocsCustomGroupTemplate">
            <Controls Id="LinkDocsCustomGroupControl">
              <Button
                  Id="LinkDocsCustomGroupControlButton"
                  Sequence="5"
                  Command="SimpleAlert"
                  Image32by32="/_layouts/1033/images/formatmap32x32.png" Image32by32Left="-448" Image32by32Top="-128"
                  Description="Copies a permanent link to the clipboard"
                  LabelText="Copy Link to Clipboard"
                  ToolTipTitle="Copy Link to Clipboard"
                  TemplateAlias="o1" />
            </Controls>
          </Group>
        </CommandUIDefinition>
        <CommandUIDefinition Location="Ribbon.Templates._children">
          <GroupTemplate Id="LinkDocsCustomGroupTemplate">
            <Layout Title="LargeLarge">
              <OverflowSection Type="OneRow" TemplateAlias="o1" DisplayMode="Large"/>
              <OverflowSection Type="OneRow" TemplateAlias="o2" DisplayMode="Large"/>
            </Layout>
          </GroupTemplate>
        </CommandUIDefinition>
        <CommandUIDefinition Location="Ribbon.Documents.Scaling._children">
          <MaxSize Id="Ribbon.Documents.Scaling.Custom.MaxSize" Sequence="15" GroupId="LinkDocsCustomGroup" Size="LargeLarge" />
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler
          Command="SimpleAlert"
          CommandAction="javascript:CopyLinkToClipboard();"
          EnabledScript="javascript:EnableCopyLinkToClipboard();"/>
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>

  <CustomAction
     Id="CopyLinkToClipboardScript"
     Location="ScriptLink"
     ScriptSrc ="/_layouts/15/CustomMenuAction/CopyLinkToClipboard.js"/>
</Elements>

Open in new window


JavaScript:

// This method contains the code needed to request the unique url to the document
function CopyLinkToClipboard() {
    // First get the context and web
    var ctx = SP.ClientContext.get_current();
    this.web = ctx.get_web();
    // Get the current selected list, then load the list using the getById method of Web (SPWeb)
    var listId = SP.ListOperation.Selection.getSelectedList();
    var sdlist = this.web.get_lists().getById(listId);
    // Get the currently selected item of the list. This will return a dicustonary with an id field
    var items = SP.ListOperation.Selection.getSelectedItems(ctx);
    var mijnid = items[0];
    // Request the list item from the server using the getItemById method. This will load all properties.   
    // If needed, one could pre-request the fields to be loaded to preserve bandwidth.
    this.listItem = sdlist.getItemById(mijnid.id);
    // load the item in the context for batch operation.
    ctx.load(this.listItem);
    //Execute the actual script on the server side. Specify delegates to handle the response. 
    ctx.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}

// Delegate that is called when server operation is complete upon success.
function onQuerySucceeded(sender, args) {
    // Request url by using the get_item method. It will return the Url field type, which has a Url property. 
    var url = this.listItem.get_item('_dlc_DocIdUrl').get_url();
    // Request the name of the document. 
    var title = this.listItem.get_item('FileLeafRef');
    // Copy Link To Clipboard (Only works in Internet Explorer)
    window.clipboardData.setData('Text', url);
    // Notify the user that the link was successfully copied
    var notificationId = SP.UI.Notify.addNotification('Link Successfully Copied to Clipboard');
}

// Delegate that is called when server operation is completed with errors.
function onQueryFailed(sender, args) {
    alert('failed ' + args.toString());
}

// Method to enable/disable the button on the ribbon or ECB. 
function EnableCopyLinkToClipboard() {
    var enable = true;
    var context = SP.ClientContext.get_current();
    var selection = SP.ListOperation.Selection.getSelectedItems(context);

    // Check if more than one item is selected, disable the button if items > 1
    if (CountDictionary(selection) == 1)
        this.enable = true;
    else
        return false;
    // Check if a folder is selected
    var item;
    for (item in selection) {
        if (selection[item].fsObjType != 0)
            enable = false;
    }
    return enable;
}

Open in new window

0
Comment
Question by:brendanlefavre
  • 7
  • 6
13 Comments
 
LVL 31

Expert Comment

by:Jamie McAllister MVP
ID: 39982399
0
 

Author Comment

by:brendanlefavre
ID: 39983390
I'm trying this, but get an error when it tries to load the content type

function EnableCopyLinkToClipboard() {
    var enable = true;
    var context = SP.ClientContext.get_current();
    var selection = SP.ListOperation.Selection.getSelectedItems(context);

    // Check if more than one item is selected, disable the button if items > 1
    if (CountDictionary(selection) == 1)
        this.enable = true;
    else
        return false;
    // Check if a folder is selected
    var item;
	var _contentType = item.get_contentType();
    for (item in selection) {
	    alert(_contentType);
        if (selection[item]._contentType != 'Document')
            enable = false;
    }
    return enable;
}

Open in new window

0
 
LVL 31

Expert Comment

by:Jamie McAllister MVP
ID: 39983543
Did you get 'PropertyOrFieldNotInitializedException' or something else?

Line 13?
0
 

Author Comment

by:brendanlefavre
ID: 39983571
I'm getting "Object doesn't support property or method 'get_contentType'" on line 13
0
 
LVL 31

Expert Comment

by:Jamie McAllister MVP
ID: 39983617
// Check if a folder is selected
    var item;
	var _contentType = item.get_contentType();

Open in new window


Looking at the above code, Item gets declared but never initialized to any type of object?
0
 

Author Comment

by:brendanlefavre
ID: 39984517
what do I need to do to get the object initialized?
0
Comprehensive Backup Solutions for Microsoft

Acronis protects the complete Microsoft technology stack: Windows Server, Windows PC, laptop and Surface data; Microsoft business applications; Microsoft Hyper-V; Azure VMs; Microsoft Windows Server 2016; Microsoft Exchange 2016 and SQL Server 2016.

 
LVL 31

Accepted Solution

by:
Jamie McAllister MVP earned 500 total points
ID: 39985306
Check out the sample from the link I sent (shown below).

After getting the selected item, the actual list item instance is obtained; this.listItem =  list.getItemById(items[k].id);

Then in the Product received function it looks like your code except the Var is initialized as so;
var item = this.listItem;
              var _contentType =  item.get_contentType();



var listItem;
function someFunction()
{
var ctx = SP.ClientContext.get_current();            
            items = SP.ListOperation.Selection.getSelectedItems(ctx);
for (k in items)
            {
              this.listItem =  list.getItemById(items[k].id);
              ctx.load(this.listItem,'Title', 'ContentType');
              ctx.executeQueryAsync(Function.createDelegate(this, this.productReceived), Function.createDelegate(this, this.failed));

            }
}


 function productReceived() {
              var item = this.listItem;
              var _contentType =  item.get_contentType();
              if(_contentType.get_name() == 'Document Set')
              {
                 alert('Document Set Item is selected')                 
              }
            }

function failed(sender, args) {
                alert('failed. Message:' + args.get_message());
            }

Open in new window

0
 

Author Comment

by:brendanlefavre
ID: 39987810
I have tried your suggestion, and get the following error

script error

this is how i'm calling the custom script
get content type action
0
 
LVL 31

Expert Comment

by:Jamie McAllister MVP
ID: 39988140
Please post your latest script here.
0
 

Author Comment

by:brendanlefavre
ID: 39991650
var listItem;
function someFunction() {
    var ctx = SP.ClientContext.get_current();
    items = SP.ListOperation.Selection.getSelectedItems(ctx);
    for (k in items) {
        this.listItem = list.getItemById(items[k].id);
        ctx.load(this.listItem, 'Title', 'ContentType');
        ctx.executeQueryAsync(Function.createDelegate(this, this.productReceived), Function.createDelegate(this, this.failed));
    }
}

function productReceived() {
    var item = this.listItem;
    var _contentType = item.get_contentType();
    if (_contentType.get_name() == 'Document Set') {
        alert('Document Set Item is selected')
    }
}

function failed(sender, args) {
    alert('failed. Message:' + args.get_message());
}

Open in new window

0
 
LVL 31

Expert Comment

by:Jamie McAllister MVP
ID: 39991737
It looks OK to me.

I'd put some diagnostics after var item = this.listItem; to ensure you really have a List Item at that point. Put some Alerts in there to examine the item title or whether it's null. That will narrow down the investigation as to whether there's an item or .get_contentType() is the problem.
0
 

Author Comment

by:brendanlefavre
ID: 40085310
I got this work, and will post the final code
0
 
LVL 31

Expert Comment

by:Jamie McAllister MVP
ID: 40085585
Good work!
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

The Scenario: Let’s say you have a quote worksheet in Excel that you use to work up sales figures and such for your clients. You utilize SharePoint to manage and keep track of these documents. You would like values from your worksheet to populate Sh…
We had a requirement to extract data from a SharePoint 2010 Customer List into a CSV file and then place the CSV file into a directory on the network so that the file could be consumed by an AS400 system. I will share in Part 1 how to Extract the Da…
Migrating to Microsoft Office 365 is becoming increasingly popular for organizations both large and small. If you have made the leap to Microsoft’s cloud platform, you know that you will need to create a corporate email signature for your Office 365…
In this video I am going to show you how to back up and restore Office 365 mailboxes using CodeTwo Backup for Office 365. Learn more about the tool used in this video here: http://www.codetwo.com/backup-for-office-365/ (http://www.codetwo.com/ba…

863 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now