This was a triumph.
I'm making a note here: HUGE SUCCESS.

Search This Blog

Wednesday, November 27, 2013

UPDATE: How to show calendar events in modal dialogs in SharePoint 2013

I recently just noticed that my code for showing events in a calendar in a modal dialog does not always do its job. It appears that when you change to another month and then try to open an event in that month (or in any other month, since it fails the moment you change the month), the event won't open in a modal dialog! This also seemed to be the case when you changed the year.

Since I didn't just want to run the script whenever a user clicked a certain element (like those for the months and for the year), I came up with a different and rather easy fix.
I decided to just run the code everytime the user clicks anywhere inside the #content div. Don't worry, it won't alter any link inside your navigation, only those that have "DispForm.aspx" at the end.
// When called, this function opens the dialog.
function openDialog(pUrl) { 
var options = {
 width : 600,
 height : 400,
 url : pUrl };
 SP.SOD.execute("sp.ui.dialog.js", "SP.UI.ModalDialog.showModalDialog", 
  options);
}

// When called, this function makes sure each event in the calendar is
// opened in a modal dialog instead of on a new page.
function clickMe() {
 $('a[href*="DispForm.aspx"]').each(function() {
  $(this).attr("onclick", "openDialog('" + $(this).attr("href") + "')");
  $(this).attr("href","javascript:void(0)");
 });
}

window.onload = function () {
 clickMe();
 // A timeout is required for when the page first loads (if you would not
 // use a timeout, then the script won't always load).
 setTimeout(function() { 
  clickMe();
 }, 500);
 
 // When you click anywhere inside #content, it will run the function
 // "clickMe()" twice, once with and once without a timeout. 
 $("#content").click(function() {
  clickMe();
  setTimeout(function() {
   clickMe();
  }, 500);
 });
};

Please do note that it might be possible that your div has a different ID. I modified my HTML master page and I believe I added the div with #Content myself (it just wraps around the #sideNavBox and #contentBox divs), but if you're using the Seattle HTML master page, then you'll need to replace the code for the #content div (which I commented in the code below) with the code for #sideNavBox and #contentBox.
 //$("#content").click(function() {
 // clickMe();
 // setTimeout(function() {
 //  clickMe();
 // }, 500);
 //});

 $("#sideNavBox").click(function() {
  clickMe();
  setTimeout(function() {
   clickMe();
  }, 500);
 });
 $("#contentBox").click(function() {
  clickMe();
  setTimeout(function() {
   clickMe();
  }, 500);
 });

Or you could just modify your HTML master page as well and place a wrapping div around #sideNavBox and #contentBox.

Do make sure that you put a reference to this script on the page with the calendar. I mentioned this in my previous post but I'll say it again in case this is the first time you read about this.
I saved my code in a file named "calendar.js", under a folder named "Scripts" in the "Style library" directory.
Edit the page with the calendar, and at the bottom of a page, add a new script editor web part. Add the following code to that web part:
<script src="/Style%20Library/Scripts/calendar.js" 
type="text/javascript"></script>

Now save the page, make sure it is checked in and published, and try it out. If all went well, you'll now be able to open events in a calendar in a modal dialog! ;)

If you have any questions, do not hesitate to ask.

17 comments:

  1. Thanks for the great post and the great information. I am having an issue with SharePoint 2013 and IE.
    1) When clicking on an event after the initial page load I need to click the event twice to pop open the modal.
    2) This is a big one. In IE when I click on the event IE is popping open another tab with javascript:void(0) in the address bar. So the window opens in a modal but it is also popping open another tab.

    Any idea on what is happening? Thanks again for the post.

    ReplyDelete
    Replies
    1. Thank you for your interest in my post and for mentioning me your issue!
      Because of your comment, I now discovered that sometimes it does indeed not work on the first click, but it does run on the second click.

      If I click on an event in a calendar that has very few other events, the code always runs on first click. However, if I click on an event in a calendar that contains a lot of other events, it never runs on first click, but it does on second click.
      I believe this has to do with the timeout, since the more events a calendar has, the longer it takes to load. Since the timeout was triggered too soon, it couldn't run the clickMe function. I could of course increase the value of the timeout, but if you have a user who tend to be very impatient and clicks on things before they are even properly loaded, that user would still encounter the issues you mentioned.

      Therefore, I sligtly changed the code so that it will now run when the page is being loaded, rather than when it is ready. I have replaced lines 20 and 36, and after line 20 I now added a new line of code:
      clickMe();

      Please change your code so that it reflects my changes. This should basically fix the issue of modal dialogs not opening on first click.

      For the issue of the modal dialog opening in another tab, add the following line of code between line 14 and 15:
      $('a[target="_blank"]').removeAttr('target');

      This will remove the target attribute in case it has been set to open the element in a new tab.

      I hope my answer was helpful to you, please do let me know if it is working properly now! :)

      Delete
  2. This works for me as long as I show the ribbon. As soon as I hide the ribbon the script seems not to execute and I get events loading in separate tab again. I am assuming that the ribbon loads some dependent scripts that the code needs to execute. Any ideas?

    ReplyDelete
    Replies
    1. Terribly sorry for my late reply! I've been very busy the past few weeks...
      I do not quite know why it only works when the ribbon is shown. It works fine here, with or without the ribbon.
      A workaround might be to fire the script on each mouse click within a certain element; for example if the user clicks anywhere inside the "#content" div, it loads the script. Not really the most ideal workaround, but I can imagine it would get the job done. I've used similar workarounds when I couldn't find a proper solution, although I should probably fix it better.

      Delete
  3. Great post :) But this doesn't work on SP2010. Could you please suggest necessary changes for that?
    Thanks!

    ReplyDelete
    Replies
    1. I'm not familiar with using SP2010, but my guess is that line 7 from the first code snippet (starting with "SP.SOD.execute") has something to do with it.
      You could check if you can open an empty modal dialog on page load, and if that works then you can browse the source code of the page on which you want to apply the custom modal dialog and see what element you need to change in order to avoid it opening in a new window or tab. Then just replace the values for the onclick and href attributes of the element that holds the url to the item, with the code to launch a modal dialog.
      I'm sorry it took me so long to reply, but I haven't been busy with JavaScript in a while (currently learning C#, starting to get the hang of it). Please do let me know if you made any progress since your comment, I'll do my best to reply faster this time!

      Delete
  4. Hi Magali,

    Thank you for the script. It looks great but I cannot get it to work. I created the calendar.js file just as you have above and used the #sideNavBox and #contentBox but it does not work for me. I even tried to use ms-acal-title as that ultimately is the link I want to open in the dialog (it is the only link that opens in the calendar). As I am not that familiar with programming, could the problem stem from the URL that is trying to be opened? I notice your code has 'a[href*="DispForm.aspx"]').each(function() in it. When I hover over the link I want to open in a dialog, it looks like this: ...../Project%20Calendar/DispForm.aspx?ID=49

    Cound the "?ID=49" at the end throw this off? Does it expect to only have "DispForm.aspx" at the end and nothing else? Should there be a wildcard in the JavaScript to account for the "?ID=##"?

    Brent

    ReplyDelete
    Replies
    1. Hi Brent,

      When you hover over the link, it should show "javascript:void(0)" instead of the URL. It does not expect to only have "DispForm.aspx" at the end. Line 14 has the selector "*=" in it, which means "is contains" (documentation can be found here: http://api.jquery.com/category/selectors/). So that line just checks if the URL contains "DispForm.aspx", and if it does, it will fetch the value of the onclick attribute and assign a new value of it. Same goes for the href attribute, which is then replaced by "javascript:void(0)".
      Did you check your browser console for errors? Maybe something is in conflict with my script, Wildcards aren't required here, it should have no problem with the ID in that link.

      Do beg me pardon for replying this late, I rarely have time to check my blog but I try to do my best. Let me know if there's an error in the console or if the problem could be solved!

      Delete
  5. Am new to sharepoint .. Am using my custom master page then how to show display form in modal popup

    ReplyDelete
    Replies
    1. At the bottom of my article, I explained how you should add a reference to this script. You do not need to add it to your master page, just add a reference to this script in a script editor web part which you best add to the bottom of the page on which you want to use the script.

      Delete
  6. Hi! Thanks a lot for the code. I have tried adding it to the page both with the script editor and by adding the code directly on the page (with SPD). None of these ways seem to make it work.

    I have checked the browser's debugger and I get an error on the the ClickMe() function saying "Object expected" and on the first line of this function ( $('a[href*="DispForm.aspx"]').each(function() { ) I get "$:undefined".

    Any ideas?

    Thanks a lot!!!

    ReplyDelete
    Replies
    1. I'm sorry for my late reply! I've been neglecting my blog again...
      I never add code directly to a page using SPD, so I'm not familiar with that. But usually the script editor web part does the trick. Do make sure you put the script tag on one line, I've split it up in two lines in my post here but that was because I wanted to improve the readability. Other than that, check if your jQuery is working properly.
      About the object expected error, I'd think it's due to either bad HTML syntax or an invalid source. Check if you're calling the function properly.

      Delete
  7. I've used a variation of this excellent script - many thanks, it's very much appreciated! However I was finding that as I was using calendar overlays, I was getting default times added in (which I didn't want), so I added this in to the ClickMe function to get rid of them:
    $('.ms-acal-sdiv').each( function(){ $(this).html($(this).html().replace(/12:00 am/g,''));});
    And also this css to get rid of other time fields:
    .ms-acal-time {display:none;}

    ReplyDelete
    Replies
    1. I'm glad to hear my script was of use to you!. Also thank you for sharing your code!

      Delete
  8. Hi Brent,
    I have same problem as you had it- I am also getting DisplayForm.aspx?ID=12, did you got any fix as Magali De mentioned ,

    ReplyDelete
  9. Hi Bret,
    Did you got any fix for DisplayForm.aspx?ID=42 , I am also getting same, I tried as Magali De shown here , but didn't find anything,

    ReplyDelete
  10. Thank you so much for this code! One thing to note, Jquery is required. I made the mistake of not including it on my first attempt at using your solution and was confused for a bit xD

    ReplyDelete