Friday, July 27, 2012

Custom Callouts in the SharePoint 2013 Metro UI, Part 1: Basics

Next: Custom Callouts in the SharePoint 2013 Metro UI, Part 2: Actions
Back to contents.



A concept of callouts in SharePoint 2013 Metro UI


SharePoint 2013 introduces a Metro-style approach to the UI design. One of the new concepts there are the callouts. Here’s the definition from the ‘Apps for SharePoint UX design guidelines’ article:
These provide relevant contextual information and actions around a particular item. Callouts are generally used to show the user more information or actions about an item in a lightweight UI.
Let’s look at some examples. Here’s the additional info for the document inside the document library:
And here’re the task details from the timeline:
So the callout is the kind of interactive super tooltip – it has a title, a content and even a command menu.

The callout structure

Let’s examine the structure of the callout UI.

title

It’s a little area at the top of the callout. The title isn’t required – there will be no such area if you don’t set its value.

content

It’s the main information area of the callout. .

close button

It’s the one of the ways to close the opened callout. The callout may be closed by:
  • the mouse click on the close button
  • the mouse click on the area outside the callout
  • by the ESC button
There can be no close button on the callout – if the callout is opened on mouse hover instead of click and if the callout is opened programmatically.

commands area

There can be a commands area at the bottom of the callout. It contains a menu with one or several actions. If there are no commands the corresponding area will not be shown.

beak

It’s a small arrow-like element visually connecting the callout with its source. It can be placed on top/bottom or the left/right side of the callout according to the chosen callout positioning scheme.

SharePoint 2013 callouts framework

If you want to employ this concept in your custom solution (app or webpart etc) to provide design consistency with the SharePoint UI you can create custom callouts. There’s a special “framework” to create and show callouts in the SharePoint 2013. As the dialogs framework known from the SharePoint 2010 the callouts framework resides in the out-of-the-box javascript files in the LAYOUTS folder. The main part of the framework is defined in the callout.js file.

How to create a callout

In order to use the callout you have to create it. Note thet the creation of the callout is not the same as the opening – callout is created once and then can be opened/closed many times.
To create a callout you need:
  1. Choose the HTML element in your UI that will be the source for callout positioning and for events (click or hover) to open the callout. It’s called the “launch point” in the callouts framework terminology.
  2. Configure the options for your callout
  3. Call the CalloutManager to create the callout

The launch point

Every callout need the so called “launch point”. It’s an HTML element which will be the source for positioning and opening events for the callout. If you choose the click event to open callout then the click on the launch point element will trigger the opening of the callout.
There can be only one callout associated with the specific launch point element at any given time. If you’ll try to create another callout for the same launch point there will be an error. If you need to create new callout for the launch point you have to remove the old ones first.
// choose the launch point HTML element
var launchPoint = document.getElementById('calloutDiv');

Callout options

To specify the callout parameters you need to configure an instance of the CalloutOptions class. It’s required by the CalloutManager while creating the callout.

// configure options
var calloutOptions = new CalloutOptions();
calloutOptions.ID = 'calloutID';
calloutOptions.launchPoint = launchPoint;
calloutOptions.beakOrientation = 'leftRight';
calloutOptions.content = 'content';
calloutOptions.title = 'title';

Call the CalloutManager

When you have the launch point and the callout options prepared you need to call the CalloutManager.createNew method to create and obtain the callout instance. CalloutManager is the kind of singleton used to manage callouts life cycle – to create, obtain, use and destroy callouts instances.

// call the CalloutManager to create the callout
var callout = CalloutManager.createNew(calloutOptions);

Here’s the result – the created callout is shown on click to launch point div:


To be continued

It's only the start of my research of the callouts framework. In the next articles we'll explore how to:
  • create actions
  • manage already created callouts
  • configure all the available callout options
  • open callouts configured to open programmatically (without hover or click event)
  • and more...

Stay tuned and feel free to comment, correct or share this article. You can reach me here or at mail@alexboev.com

Next: Custom Callouts in the SharePoint 2013 Metro UI, Part 2: Actions
Back to contents.

36 comments:

  1. Nice articles, well done!

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hi, Jason! I've read your original comment via email. Did you resolve your problem?

      Delete
  3. Took me a while to figure out you need the following lines to include the callout class (dont download the .js files from Sharepoint onPrem).
    s c r i p t type="text/javascript" src="/_layouts/15/init.js">
    s c r i p t type="text/javascript" src="/_layouts/15/mQuery.js">
    s c r i p t type="text/javascript" src="/_layouts/15/sp.ui.dialog.js">
    s c r i p t type="text/javascript" src="/_layouts/15/sp.runtime.js">
    s c r i p t type="text/javascript" src="/_layouts/15/sp.js">
    s c r i p t type="text/javascript" src="/_layouts/15/callout.js">

    ReplyDelete
  4. Very nice article. Iam impressed with your article and wrote my understanding on Callouts here

    http://sureshpydi.blogspot.in/2013/03/sharepoint-2013-call-outs-creating.html

    ReplyDelete
    Replies
    1. I'm glad you like it. Please note that my article has three parts at this moment. I hope you can find some useful info in another parts.

      Delete
    2. Yes Alex. I checked all the parts. Very useful information. Thanks for the posts.

      Delete
  5. Hi, I am following the codes provided but it is not showing. The Callout Popup is not showing.
    I have added the .js files listed by Christian but still no luck.

    Am I missing something?

    ReplyDelete
    Replies
    1. Hi!

      It's hard to suggest a solution without looking at the details. Can you provide me with your page markup?

      Delete
    2. Hi Alex,

      I am having this error:
      CalloutManager: Required property must be defined: launch point

      s c r i p t type="text/javascript">
      ExecuteOrDelayUntilScriptLoaded(CreateCallOutPopup, "callout.js");
      function CreateCallOutPopup()
      {
      var targetElement = document.getElementById('NotificationDiv');
      // configure options
      var calloutOptions = new CalloutOptions();
      calloutOptions.ID = 'notificationcallout';
      calloutOptions.launchPoint = targetElement;
      calloutOptions.beakOrientation = 'leftRight';
      calloutOptions.content = 'content';
      calloutOptions.title = 'title';
      var callout = CalloutManager.createNew(calloutOptions);
      }
      /s c r i p t>

      d i v id="NotificationDiv" style="width:50px;">
      s p a n id="ms-pageDescriptionImage"> /s p a n>
      /d i v>

      Delete
    3. Hi Alex,

      I have managed to get the above working. However, I am facing another error:
      'IsElementRtl' is undefined

      Delete
    4. Yes, that's because 'var targetElement = document.getElementById('NotificationDiv');' gives you a NULL. So you assign a null to the launchPoint property but it's required. I've already answered below - you need to execute your code later in the page cycle and there's _spBodyOnLoadFunctionNames that can help. You need to use it instead of ExecuteOrDelayUntilScriptLoaded. Once again - see my modification of your code here: http://pastebin.com/qQUAtvsk - it works well.

      Delete
    5. The blogger's comments thread is so plain and inconvenient! :( Anyway it seems here you can find a solution for 'IsElementRtl' is undefined: http://sharepoint.stackexchange.com/questions/64720/callout-popup-is-not-working-in-app-part

      Delete
    6. Hi Alex , I have custom list with content type is document library and I want to custom callout menu for the item in this list. I used the same code but I can't done this. Can you help me custom this? Thank for your help.

      Delete
    7. Hi, Anonymous!

      What's your goal in detail? Have you considered a simple ECB (standard list item dropdown)customization?

      Delete
  6. Hi Alex,

    I have added the below using the "Embed Code" in the SharePoint page

    Script Section:
    ExecuteOrDelayUntilScriptLoaded(CreateCallOutPopup, "callout.js");
    function CreateCallOutPopup()
    {
    var targetElement = document.getElementById('LaunchCallout');
    var calloutOptions = new CalloutOptions();
    calloutOptions.ID = 'notificationcallout';
    calloutOptions.launchPoint = targetElement;
    calloutOptions.beakOrientation = 'leftRight';
    calloutOptions.content = 'content';
    calloutOptions.title = 'title';
    var displayedPopup = CalloutManager.createNew(calloutOptions);
    }

    Div section with ID=LaunchCallout
    Launch Callout

    ReplyDelete
    Replies
    1. Hi! I've tested your code and have found your problem. Your script is running too early - when your div isn't loaded yet. So your code breaks on the line with document.getElementById. Here's the working modified version: http://pastebin.com/qQUAtvsk

      Delete
  7. Really great post i learnt something new !

    why are we replacing "ExecuteorDekayuntilScriptLoaded" with _spBodyOnLoadFunctionNames.push ?

    ReplyDelete
    Replies
    1. Hi! I'm glad you like it! As for the _spBodyOnLoadFunctionNames vs ExecuteorDelayuntilScriptLoaded - in my test case the _spBodyOnLoadFunctionNames was sufficient but now I think your're right and it's more reliable to use ExecuteorDelayuntilScriptLoaded because in order to employ the callout framework we have to make SP api calls: http://blog.fidelityfactory.com/2012/04/03/when-to-load-my-ecma-script/

      Delete
  8. If a new column is added to a document library, is it possible to add the contents of the new column to the OOTB callout (content section) that is on the document library. Everything I've read to date references creating a new callout - I want to modify an existing OOTB one

    ReplyDelete
    Replies
    1. Hi! I've already interested in such question and my own little research on the subject tells that it's not possible to do that from the *application* (the new SharePoint "app" model) because your client code is hardly restricted in access to the hosting SharePoint site. You're certainly can do it with the traditional farm solution or sandboxed solution if it's acceptable to you - there you can define any client code with access to the library list view page markup and to the callout framework. I think it's possible to do this way.

      Delete
    2. Hi again! I've made a research on the subject: http://blog.alexboev.com/2013/08/custom-callouts-in-sharepoint-2013.html

      Delete
  9. Thanks a lot Alex for such a detailed explanation.

    I am using exact same thig but got into something. I am not getting any error but found that CallOutPopup is not opend up. I checed with callout.isOpen() function which returns false. When I click on the same element second time it opens up. This looks strange to me.

    Can you please let me know why its closed on first click and visible on second click?

    ReplyDelete
    Replies
    1. Hi! I'm not so big expert in callouts - I just have made some experiments with them. Anyway it's hard to suggest from your description - I need the details. Can you share your code with me - I can try to look.

      Delete
  10. You would expect the callout content to be dynamic, like only fetch this information when the user asks for it (by clicking on the launchpoint). However I don't see such examples.

    ReplyDelete
    Replies
    1. Hi Anonimous!

      It an interesting question! I've made a research for you and here's the result: http://pastebin.com/ZM4Xs7Zj The interesting part is around callout.addEventCallback. See the comments in my code. Hope it helps. Please note that there are 'opening', 'opened', 'closing' and 'closed' events you can subscribe. Another important part is that you have to find the element with the specific generated ID to change the real content of the callout without break of the other structure elements such as title and close button.

      Delete
    2. Oh, thanks a lot for your research and posting your result! (I will look into it tomorrow.)

      Delete
  11. Hi Alex Boev

    I have a html structure similar to : ""
    And I'm trying to display "callout" when user clicks on the image.
    so I'm creating "callout" on the anchor tag.
    But when I'm clicking on the image it's not showing the callout.
    Can u figure it out for me..

    -Sarat

    ReplyDelete
    Replies
    1. and the image tag is nested inside the anchor tag

      -Sarat

      Delete
    2. Sorry I doesn't understand your current setup from your description. Can you provide the minimal example code and markup you've created?

      Delete
  12. CalloutOptions is not defined says for me... I still cannot find the solution callout.js is already loaded on page but callout not working

    ReplyDelete
    Replies
    1. It's hard to diagnose such a generic problem without examining of the real example. I can try to help if you provide me with the working examplein the Office 365 trial for example.

      Delete
    2. SP.SOD.executeFunc("callout.js", "Callout", YourCallback)

      Delete
  13. Hello, I am getting "launchPoint given is already associated with a callout" error. It is not making problem to show callout but why i am getting this error?

    ReplyDelete
    Replies
    1. Hello! The error message is quite self explanatory - the HTML element that you use to create a callout was already used for the same task. You need to remove the previous callout before using the element as the launch point for the new callout. Another option is to use different HTML element as the launch point.

      Delete
  14. Hi, and thanks for your article. I have a question. I am just trying to view regular document library document (item) ECB in a custom application by passing List id and/or list item id and/or item url. Can you provide some example how to do that? All i need is to click a link and have the default metadata properties that show on out--of-box sharepoint library ECB menu. Thanks, Max

    ReplyDelete