?
Solved

Custom Ribbon Action - Disabled with Document Set Selection

Posted on 2014-04-06
13
Medium Priority
?
804 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 6
13 Comments
 
LVL 32

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 32

Expert Comment

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

Line 13?
0
What Is Blockchain Technology?

Blockchain is a technology that underpins the success of Bitcoin and other digital currencies, but it has uses far beyond finance. Learn how blockchain works and why it is proving disruptive to other areas of IT.

 

Author Comment

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

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
 
LVL 32

Accepted Solution

by:
Jamie McAllister MVP earned 2000 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 32

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 32

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 32

Expert Comment

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

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

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

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…
A recent project that involved parsing Tableau Desktop and Server log files to extract reusable user queries for use in other systems. I chose to use PowerShell to gather the data, and SharePoint to present it...
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

762 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