Azure / Office 365 / SharePoint Development / Search

Adding a custom action to a callout in SharePoint 2013

October 02, 2013

A couple of weeks / months ago I wrote a blog post about how to you could hide the default social actions in the callout menu of a document library (blog post). The trick to remove these actions was to override the footer template rendering of the callout.

This week I had the opposite question, how can you add a custom action to the callout with preserving the default actions. The first part isn't that difficult, but the last part "preserving the default actions" is.

Solution

First things first, we start by adding a new custom action to the callout. When you want to add a new action to the callout, you will need to render a new footer template for the callout.

The code above will create a "Custom action" action to the callout.

Custom action in callout

Custom action in callout

As you can see the problem is that you lose the other actions, because the default footer was overridden.

To re-add the default actions, you have to call the SharePoint function that creates these actions. The downside is that these functions are different for each list / library.

Library: CalloutOnPostRenderTemplate(renderCtx, calloutActionMenu)

My Documents Library (Skydrive Pro): myDocsActionsMenuPopulator(renderCtx, calloutActionMenu)

Asset Library: AssetLibraryCalloutActionsMenuPopulator(renderCtx, calloutActionMenu)

Once you know which function you need to call, it is just a matter of adding it to the code.

Note: Line 10 needs to be changed in order to make it work on other list / library templates.

Default actions added to the callout

Default actions added to the callout

Why is my follow action gone?

That is correct, the default functions from the library and asset library don't add the follow action by default. This action is added when the Follow Content feature on site level is activated. This feature adds a script block to the page where it overrides the default rendering of the callout of the libraries.

You can re-add the follow action like this:

Custom action + Default actions + Follow action

Custom action + Default actions + Follow action

As you can see it's possible to add your custom actions, but it involves a bit of extra coding.

Comments

  • Nick Hurst

    Is there anyway to add the “Edit Properties” option to the callout menu?

    • Nick,

      You can add the following action to the callout:

      Regards,
      EStruyf

    • FVK

      an even better to get the URL would be:

      SP.UI.ModalDialog.ShowPopupDialog(renderCtx.editFormUrl + “&ID=” + renderCtx.CurrentItem.ID);

      • FVK,

        Thank you for the feedback.

        Regards,
        Elio

  • Nick Hurst

    That’s awesome, thanks Elio. Another question though, in my testing yesterday I noticed that by replacing the footer template, for some reason this results in different behavior for the Edit button in some browsers. So for example in chrome, before the modifications the Edit button prompts to open the file in the office application. After the modifications, chrome just downloads the document.

    So considering the fact that I need to preserve the native Edit button functionality, do you think it would be possible to add the Edit Properties either above or below the native footer template?

    • Nick,

      I’ve just tested this really quick, but I didn’t saw any difference between the browsers. I’ll keep it in mind to test it when I have more time.

      If you want to add it above the footer, you can do that by changing the body template instead of the footer.

      Regards,
      EStruyf

  • Nick Hurst

    The browser differences we were seeing was actually caused by having SPD 2013 installed with Office 2010, and then using either IE or Chrome. It’s a totally seperate bug that occurs even with the default callout.

    Thanks again.

  • Saratchandra

    Hi I need to show the number of times a page was visited on the corresponding callout popup of the page-document, without disturbing the other actions…How can I achieve that??

    • Saratchandra,

      Maybe you could use the same approach as the hover panels from the search centers, there you’ll also have the number of views at the top. I suggest to check if you could use these functions.

      Regards,
      Elio

  • FVK

    Hi Elio,
    I am desperate about how to security trim some of those customActions. For example, i’d like to hide the Edit Properties if the current user can only read the selected item.

    I am able to perform the permission check and add the custom actions using CSOM, but the trouble is: as the CSOM query is async, the rendering is done before the CalloutActionMenu is updated with additional customActions.

    If you have an idea, that could be great!

    Regards,
    FVK

    • FVK,

      Don’t think that there is another way than to doing it async.

      Another approach could be to build the CalloutActionMenu with HTML instead of adding actions. This way you could give unique IDs to the actions and could easily be removed when async call is completed.

      Regards,
      Elio

    • FVK

      Thanks, that’s where I was already heading. Thus i will have more control of the actions, using Icons for instance :)

      Keep up the good work :)

      Regards,

      FVK

      • LK

        Hello,

        I was wondering if you figured out a way to do the security trimming? I have the same requirement and I am struggling to get it working. Would you be able to describe how you did it or post an example?

        LK

        • LK,

          Just did a quick check and found out that they do a call to the HasEditPermission function which can be found in the clienttemplates.js file.

          So I think you could do something like this:

          I found it in the GetCallOutOpenText function:

          Regards,
          Elio

  • Saratchandra

    Hi Elio,

    Thanks man, I’ll try that..

  • Saratchandra

    Hi Elio Struyf
    I can use your method to show that. But I’m facing problem while fetching the total hits to the page. Download the “_layouts/15/calloutusagecontrolscript.js” and observe. At the following line,

    e.get_totalHits();

    it’s giving the error.. “Object reference not set to an instance of an object on server. The object is associated with method GetAnalyticsItemData.”
    Suggest me some way to get rid of this error…

    Thanks

    • danesh

      Hi Saratchandra
      Do you find any solution?

  • Arwena

    Hi Elio,

    I wish I could include a summary table of infopath forms located in the selected folder.

    My first track is:

    a.push(”);
    a.push(”);

    I would like to complete the table by retrieving the names and status of infopath, and put that in the custom action: edit block.

    Am I on track?

    Thanks

    • Sorry, the code is empty in the latest response:

      div class=”js-callout-body” id=callout-body

  • Hi Elio, I’ve been using your solution above to provide a ‘Edit Properties’ link for documents on the callout and it works great. The one issue we’ve run into, is the ‘Edit Properties’ opens in a page instead of in the popup modal. Which means that after you edit the properties you are returned to the default view for the library, instead of the view that you were on.

    Is it possible to capture the source of URL of the page you opened the Callout action from? That way I could append &source= to the end of the URL to the return the person to that specific view after editing the properties. Thanks.

    • Arwena

      Hi Nick, I think the solution to your problem is already in the Elio function:

      _spPageContextInfo.webAbsoluteUrl + “/” + renderCtx.listUrlDir

      Regards.

    • Arwena

      This property can also help you: _spPageContextInfo.serverRequestPath

  • Nick Hurst

    Hi Arwena, so _spPageContextInfo.serverRequestPath gets me most of the way there as it returns the view URL. The problem is that it doesn’t capture the sort or filter variables.

    So the URL from a CustomView that is sorted by Title might look like this:
    https://domain/sites/SiteName/SharedDocuments/Forms/CustomView.aspx#InplviewHash96972186-436e-4f92-b399-6dcb26216104=SortField%3DTitle-SortDir%3DAsc

    _spPageContextInfo.serverRequestPath will return everything before the #. Is there anyway to return the rest?

    Thanks!

  • Nick,

    You could retrieve the full URL of the current page with this:

    What you should need to do encoding the URL like this:

    Otherwise it could give some problems with the hash path.

    Regards,
    Elio

  • Dharni

    Hi,
    Thanks for this article. I follwed the steps and able to create custom action button. but this is working fine IE8. not in IE9 &IE10. Everytime required to refresh the page to see this custom action (navigating from other url). but default Edit, share actions are shown. Any advise on this?

    I want to customize ‘new document’ callout. how to do that? Thank you.

  • Leo

    Hy,
    Thanks for your solution, but It didn´t work for me as I didn´t want to make sure that a additional JS-File is executed on the listview. However, I found another way:
    In the “Layouts” Folder there is a clienttemplates.js, which is responsible for Rendering views. You just have to:
    -Make a copy of the file
    -Customize it according to your Needs (eg. adding or removing a Action in the function “CalloutOnPostRenderTemplate”
    -copy (or deploy) it into the layouts Folder (another Name and/or subfolder is recommended
    -set the “JSLink” property of your view to the “_layouts/15/” relative path of your new file

    Regards
    Leo

    • Leo,

      Thanks for the feedback, but I wouldn’t go for that approach, if in one of the future updates, the “clienttemplates.js” file gets update. You need to manually check if the file contents have changed, and do the steps all over.

      Regards,
      Elio Struyf

  • Leo

    In my opinion it is just a template for displaying the data. Just like the Displaytemplates used for the search results. There you also do a copy of an existing template and restyle it according to your needs. If the original is changed in a future update, there is also no effect to your template.

    As long as the customized clienttemplates.js results in the displaying the item the way I want it, I don´t care about changes in the original one.

    Executing Javascript code in order to overwrite the original template also relies on some consistencies in the file. If the file changes with an future update in some ways, it also might not work anymore and result in errors. While simply copying the file and customize it will work even when the original file changed somehow.

    And if they do major changes in the ECMA Client-API, almost any custom solution working with it will have troubles.

  • PSK

    Hi Elio,

    I copied the script into my content editor webpart placed in document library page. But its showing the default callout. I cannot see custom action added.

    Can you please guide me what am i missing.

    Regards,
    PSK

    • PSK

      Hi Elio,

      I got this resolved. The problem was because my IE10 was running in compatibility mode.
      But i observed one major issue. The custom callout items are not always visible. Most of the time i see the default callout. Only when i clear browser history and cache, it renders again.

      Can you please suggest some way out for this problem?

      Regards,
      PSK

      • PSK,

        I can’t seem to reproduce the problem you’re experiencing.
        Are you able to debug it? Does your code gets triggered when the problem occurs? Is the site feature Following content enabled on the site?
        This feature adds a JavaScript code block to the page to render the follow and share actions to the menu.
        If you placed your code block before the follow and share one, your code will be overwritten by SharePoint.

        Regards,
        Elio

        • PSK

          Hi Elio,

          Yes, the code get executed till “itemCtx.Templates.Footer = function (itemCtx) …”. But function does not get executed.

          Following content is enabled.

          I created a new javascript file which have the custom callout code and placed it in 15 hive. I added a content editor webpart at top of the document library page. Is it a right place to reference the js?

          Can you please suggest where the code should be added.

          Regards,
          PSK

  • Tomas

    Hi, I faced the same problem as you – custom action was only available on first load page, after subsequent navigation on the site it was lost. My problem was that the feature ‘following’ was activated. As soon as I deactivated it, it worked. But I wasn’t those actions to be there, so should I code FOLLOW myself or how can I tell the system to load my customizations after FOLLOW is added ?

    Thank you Tomas

    • Tomas,

      The problem with the follow feature is that it completely overrides the rendering of the footer.

      If you place the code for the custom action somewhere at the end of the page, it would get executed at the end.

      What you can also do is to turn off the feature, and add the code yourself. I placed the default code in another post follow and share code.

      Regards,
      Elio

      • PSK

        This helped.
        Thanks Elio.

      • Tu Nguyen

        hi Elio,

        Thanks for this article. I get the issue when browsing the page on IE9 and IE10, the callout Javascript seems not to be triggered. However, my client is not happy with the approach that we turn off the Following Content feature and manually add the Share and Follow button. They want to keep SharePoint as much OOTB as possible.

        So is there any solution that I can be sure my custom JS to be executed after the Following Content feature JS as you mentioned above?

        I looking forward to your response.

        Regards,
        Tu

  • Leo

    Thomas,

    you could also try to add your function, that is overwriting the Original Footer to load after Rendering with

    AddPostRenderCallback(ctx, function(){xxx}

    This might make sure that your code is executed after everything else.

    Of course you could also make a copy of the clienttemplates.js file and add your customizations there directly (as I mentioned some Posts before)

    regards

    • Tomas

      Hi, yes it worked. I’m using delegate control, so cannot really put it at the end. I coded it myself. However when “Follow content” feature is disabled you need to reference the following yourself in order the default follow script to work:

      function RegisterFollowJS() {
      RegisterSod(“userprofile”, “\u002f_layouts\u002f15\u002fsp.userprofiles.debug.js?rev=p1e1MK16xqhzgHSFHZEOOA\u00253D\u00253D”);
      RegisterSodDep(“userprofile”, “sp.runtime.js”);
      RegisterSod(“sp.ui.mysitecommon.js”, “\u002f_layouts\u002f15\u002fsp.ui.mysitecommon.debug.js?rev=CPyRijUHjdx\u00252Fq\u00252BHVt4wjuA\u00253D\u00253D”); RegisterSodDep(“sp.ui.mysitecommon.js”, “sp.init.js”); RegisterSodDep(“sp.ui.mysitecommon.js”, “sp.runtime.js”);
      RegisterSodDep(“sp.ui.mysitecommon.js”, “userprofile”);
      RegisterSodDep(“sp.ui.mysitecommon.js”, “profilebrowserscriptres.resx”);

      RegisterSod(“followingcommon.js”, “\u002f_layouts\u002f15\u002ffollowingcommon.debug.js?rev=QlAqfMuxiHOMCoHCTvpncg\u00253D\u00253D”);
      RegisterSodDep(“followingcommon.js”, “strings.js”);
      RegisterSodDep(“followingcommon.js”, “sp.js”);
      RegisterSodDep(“followingcommon.js”, “userprofile”);
      RegisterSodDep(“followingcommon.js”, “core.js”);
      RegisterSodDep(“followingcommon.js”, “mQuery.js”);
      }

  • Ankit

    Hi Elio great article…

    One question suppose if i want to implement that custom action in every list say every doc lib then how to do that ??

    • Ankit,

      Do you have a custom branding applied on your site? If so, you could add it in a script. Or you can modify the OOTB master page.
      If you haven’t or can’t, you could create a sandboxed solution to apply a script reference to the site collection.

      Regards,
      Elio

  • durga

    hi,
    how to use the code given above

  • Pingback: Add callout cu​stom action based on content TYPE « Luis Valencia - Sharepoint Architect()

  • Can you show me how to add “Download a Copy” in the callout menu?

  • mahavir

    The code works fine in IE 8 but not in IE 10. Do we need any specific change in this code or master page may be? We already have in the custom master page.

    Please suggest.

  • Gerry

    Hi Elio,

    Really helpful Article. I am wondering will it be possible to incorporate OOTB ‘Delete’ functionality for Document Library Item in this Callout. I do not want to write my custom routine.

    • Gerry,

      Thanks for the feedback. You could try the following action:

      It uses the default delete document delete action.

      currentCtx and currentItemID is needed, because a check is in place on the DeleteDocLibItem function. If they do not exist, the function is not executed.

      Regards,
      Elio

  • Do you know how to customize New Document callout? How to append templates too in the callout? help will be appreciated..thanks

  • Anmol

    Hi Elio,

    I want to add a custom action to the Pages Library in a Wiki site. But I couldn’t find a list template ID for it. I tried with 119 but it added the action for the “SitePages” library and not the pages library. I tried with 101 (which is for document libraries) but couldn’t see the action there. Can you help?

    • The page library template ID is 850.

      Regards,
      Elio

  • Alex

    Great article but your script does not work with the Timeline.. Is there a way to customize the timeline hover panel ?

  • Hi,

    You do not have to go via a webservice, you could do it with JS. There is a JS script: /_layouts/15/Reputation.js – This JS file has function called: Microsoft.Office.Server.ReputationModel.Reputation.setLike(ctx, listId, pageId, true or false);

    Hope this helps.

    Regards,
    Elio

    • Basant Pandey

      We are using external web service for like unlike the post. So need in the callout.js. Just wanted to know can we do it?

      • If that webservice is accessible from your browser, I see no problem why you cannot do that.

        • Basant Pandey

          Just wanted to know which event I can write this type of functionality. As I mentioned I am implementing in “Content Search Web part” and I am using “isEnabledCallback” function to change the the title. The service taking time to and mean while the content is rendered on the browser.

        • Basant Pandey

          Thanks for your help Elio!!! :)
          I was forget you make my call sync. That’s why it causing an issue. Ajax call i used async=false; it works for me.

  • Andy

    Hi Elio

    I want to move the Edit Properties option up one menu level. So when you click on the “…”, you see Edit Properties as the first action. Is there any way you can do this?

    Best Regards
    Andy

    https://uploads.disquscdn.com/images/7fdcd5dce62baf6791b48f29f3c8e9da2824d30d24592a1c363990c3c20fca34.jpg

    • Yes, that’s possible. In the onClickCallback function, you can define to navigate to the edit form of the document / list item: EditForm.aspx?ID=

  • simk

    Hi Elio, is there is way to security trim this actions? Can rights be set ?

  • Pepinoflexia

    Hi Elio,

    I’m a little confused about your javascript code, should I put it inside the masterpage or anywhere else?

    Thanks in advance.

    • That is up to you, it needs to be available on the page of the document library view. So you can also add it via a content editor web part or script editor web part.

  • Luc Verstrepen

    Hi Elio,
    we are experiencing the following behavior: our custom actions are visible on existing documents of a document library. However, when we upload a new document, then the custom action is not visible on the callout of the uploaded document.
    After a refresh of the page, the custom action is available on all documents.
    Is this expected behavior? Or are we making a mistake in our implementation?
    Thanks!

    • Good catch Luc! Probably the code does not triggered due to an async refresh of the list. That means you will have to bind into the refresh method of the list to get this trigger to your code.

  • Anna Vanyukova

    Hi Elio,
    Do you know how to apply this custom action for OneDrive library? I used function myDocsActionsMenuPopulator(renderCtx, calloutActionMenu) but don’t khow how to distribute for all existing personal sites js file
    Thanks!

    • If you want to automate it, you best create a PowerShell script to add it to all personal sites.