Feedback from any page, using 2010’s page dialogs

SharePoint 2010 is nice. It has lots of nice features, including a nifty one that pops up a Dialog on screen when you want to create a new list item, then auto-refreshes the page that the item was triggered from (so the item appears in the current view if it’s configured to do so).

In my current project I get to look at ways to leverage the standard SharePoint functionality and build something sexy – which is a lot of fun. One of the things recently requested was a way for users to provide feedback from any page. Initially, this was pretty easy to build into the page layout using a JavaScript function triggered by an onClick event

onClick="javascript:window.location='/lists/ContentFeedbackList/NewForm.aspx?Source=' + window.location"

Nice… it worked, and always took the user back to the original page. But it was a standard form in the browser (soooooo SharePoint 2007), and it didn’t have the “slickness” of the “New Item” dialogs in SharePoint 2010… so once I met the original requirement and finding myself with a little time on my hands, I went about seeing how it could be optimised for a better user experience.

Requirements:

  1. Feedback link dynamically generated for any page it appears on
  2. Feedback to include URL to source page by default (but user editable)
  3. User to Submit feedback (or not)
  4. Message to user notifying them that their feedback has been received (or not)
  5. Dialog to close when Save, Close, Cancel or X is clicked
  6. User to end up at their original page where feedback was submitted from

There are 2 “SharePoint-native” ways of getting a New Item Dialog to appear: NewItem2(event, URL) – This one appeared to work, but did not close when any Close or Cancel buttons were clicked – instead it reloaded the “Source” URL into the dialog window (which is not the expected behaviour, so it did not meet requirement 5) – You could also not easily get requirement #4 working either (I mean, JS alerts are fine but they’re a bit 1990’s, and you would need to change the “NewItem.aspx” page)… so after some fiddling this option was dismissed.

[EDIT]

Actually, by adding the &IsDlg=1 parameter to the QueryString, the Cancel buttons behaved themselves… but it still didn’t tell the user what had just happened… Also there was no way to set the value of the Dialog – it just came up with “Content Feedback List – New Item”. Bah!

The other alternative is SP.UI.ModalDialog.showModalDialog – Ahhh, now we’re talking – this particular function takes an array of “Options” that describe the windows attributes and behaviour… http://msdn.microsoft.com/en-us/library/ff410058.aspx

So if we can leverage this, then we should be able to meet most of the requirements…

<script type="text/javascript">
    function openDialog() {
        var options = {
            url: '/Lists/ContentFeedbackList/NewForm.aspx?SourceDialog=' + escape(window.location) + '&RootFolder=%2FLists%2FContentFeedbackList&ContentTypeId=0x01008F4DE574C6774E4BA178106B7759AAA9',
            title: "Provide Feedback",
            dialogReturnValueCallback: feedbackReceived,
            allowMaximize:false
        };
        SP.UI.ModalDialog.showModalDialog(options);
     } 

function feedbackReceived(dialogResult, returnValue) {
    if(dialogResult == SP.UI.DialogResult.OK) {
        SP.UI.Notify.addNotification('Feedback Submitted!');
    }

    else {
        SP.UI.Notify.addNotification('Feedback Cancelled...');
        return false;
    }
}

        </script>
         <b><a href="#" onclick="javascript:openDialog();return false;" target="_self"><span style="font-size:12pt"><img src="/PublishingImages/arrow_btn_right.gif" style="border:0px;padding-right:5px" alt="Page Feedback"/>Feedback</span></a></b>

Okay now we have a link on the page – once clicked, it fires the js function called openDialog() – which creates the Options array and then calls the SharePoint function SP.UI.ModalDialog.showModalDialog, passing the options array in as the parameter.
The dialogReturnValueCallback option allows us to pass the returned dialog window parameters back to a post-dialog function which then assesses the outcome and writes the appropriate message to the screen.

There are 2 main ways to have an alert appear on the screen, using the standard SP2010 UI:

  • The SP.UI.Notify.addNotification function that I have used (http://msdn.microsoft.com/en-us/library/ee658473.aspx) – this slides an “alert” in on the far right of the screen, just below the ribbon
    • For me, this was ideal because that’s also where the Feedback link is on my page layout. The option to make it “sticky” was not necessary for the feedback alert, so I have let it die off automatically.
  • The other is SP.UI.Status.addStatus (http://msdn.microsoft.com/en-us/library/ff407795.aspx, http://msdn.microsoft.com/en-us/library/ff412058.aspx) –
    • This generates a “Status”bar below the ribbon that spans the width of the page (If you have ever had errors in your Central Admin “Health Monitor” and seem the Red bar that appears near the top of the page, this is the same one).
    • This option is a lot more noticeable, but does support different colours (green yellow red blue), allows you to send updates to existing alerts and stays there until closed by the user.

Jumping back to the original requirements, we have now addressed 1, 3, 4 and 5 – but what about 2? Gotcha covered… in the “url” option above, there’s a QueryString parameter called “SourceDialog” – this is one I made up, could also be called TeddyBear or anything you want – the point is, when the Dialog page is called, the entire URL of the current page (window.location in javascript-speak) is passed to the Dialog via the “SourceDialog” parameter… which another piece of code (based on some work by Mark Rackley / SharePoint Hillbilly) picks up and uses to prepopulate the relevant field.

<script type="text/javascript">
//spbodyOnload not required for 2010
//_spBodyOnLoadFunctionNames.push("getTagFromIdentifierAndTitle");

//store the query string
    var qs = location.search.substring(1, location.search.length);
    //split query string by name value pairs
    var   args = qs.split("&");
    var vals = new Object(); 

  //loop through name value pairs and store
    //in a hashmap using field name as key
    for (var i=0; i <   args.length; i++) {
    var nameVal = args[i].split("=");
    var temp =   unescape(nameVal[1]).split('+');
    nameVal[1] = temp.join(' ');
    vals[nameVal[0]] = nameVal[1];
    }

//getTagFromIdetifierAndTitle
//Get form field by type & title
//parameters: tagName: type of tag to return ('input' & 'select' are the ones I use)
// identifier: Optional identifier of the tagName in question
// title: The specific title (name) of the field you would like to retrieve
//returns: field object to set or get value of (or do whatever you want I guess)

function getTagFromIdentifierAndTitle(tagName, identifier, title) {
     var len = identifier.length;
     var tags =   document.getElementsByTagName(tagName);
     for (var i=0; i <   tags.length; i++) {
     var tempString = tags[i].id;
     //if you are not sure what the actual title of your field is, uncomment this alert
     //alert(tags[i].title);
     if (tags[i].title == title && (identifier == "" ||   tempString.indexOf(identifier) == tempString.length - len)) {
       return tags[i];
     }
     }
     return null;
}

  var theTextBox = getTagFromIdentifierAndTitle("input","","Page Feedback Relates to");
if (typeof vals["SourceDialog"] == "undefined") {
theTextBox.value = encodeURI(window.location);
//alert("issue");
}
else{
theTextBox.value = encodeURI(vals["SourceDialog"]);
//alert("No issues");
}
//theTextBox.disabled=true;
</script>

If it cannot find this parameter, it just populates the current page’s URL…

Once you put the components together, this is the functionality you get:

DialogPopup
Of course, since we’re populating a list we can attach workflows to it – In my case, any feedback that gets responded to can also be “promoted” into an FAQ list – so the more questions that get asked, the more answers are created for the FAQ. Sweet!

Once the Feedback is Submitted, the user returns to their original page (which has been waiting patiently in the background) and a message comes up like so…

FeedbackSubmitted

I have used a couple of .TXT files in a common version-controlled Site Collection Code library and embedded them using the CEWP’s “Content Link” option. With the generic site pages, the CEWP was added into the Page Layout just below the “Categories” option in the screenshot above from SharePoint Designer (so that users could not modify it).
For the code in the “New Item” page for the Feedback list, I dropped in the CEWP and linked to the second file from the SharePoint UI.

Both files can be downloaded here – Download. There are of course better ways to implement this (eg as a solution), and there are opportunities to enhance the error handling of the js code, but it’s a decent starting point if you want to achieve similar goals and you are working in a dev / prototype environment like I am.

Thanks go to Chak – http://www.chakkaradeep.com/post/Using-the-SharePoint-2010-Modal-Dialog.aspx – and Johnathan – http://blogs.msdn.com/b/jfrost/archive/2009/11/08/how-to-display-a-sharepoint-dialog-from-ribbon-button-and-get-selected-item-context.aspx – and Mark Rackley – http://geekswithblogs.net/SoYouKnow/archive/2009/07/06/setting-sharepoint-form-fields-using-javascript.aspx whose blogs provided the foundations for this solution. Mark particularly – that code block will be going into my toolkit for sure.

Cheers!

UPDATE 2013: in 2013, you need to load the JavaScript file before you can run the query, so instead of this:

function openDialog() {
    var options = {
       url: '/Lists/ContentFeedbackList/NewForm.aspx?SourceDialog=' + escape(window.location) + '&RootFolder=%2FLists%2FContentFeedbackList&ContentTypeId=0x01008F4DE574C6774E4BA178106B7759AAA9',
       title: "Provide Feedback",
       dialogReturnValueCallback: feedbackReceived,
       allowMaximize:false
    };
    SP.UI.ModalDialog.showModalDialog(options);
 }

We use this:

 function openDialog() {
    var options = {
       url: '/Lists/ContentFeedbackList/NewForm.aspx?SourceDialog=' + escape(window.location) + '&RootFolder=%2FLists%2FContentFeedbackList&ContentTypeId=0x01008F4DE574C6774E4BA178106B7759AAA9',
       title: "Provide Feedback",
       dialogReturnValueCallback: feedbackReceived,
       allowMaximize:false
    };
    SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', options);
 }

Note the different way we are calling the showModalDialog function…

This guy has a lot of good tips on the OOTB SharePoint 2013 modal dialogs –
http://blog.collabware.com/tag/sp-ui-modaldialog/

Advertisements

About Brad Saide

I'm a SharePoint consultant. I'm also slowly going bald, seem to have a permanent spare tyre around my waist and enjoy socialising with friends over a beer or 10. The last 2 may possibly be related. Started working with SharePoint when the first version was in limited beta release (participated in the Technology Adoption Program while at Woolworths) and have been committed to the adoption of the technology as a business enabler ever since.
This entry was posted in Uncategorized. Bookmark the permalink.

13 Responses to Feedback from any page, using 2010’s page dialogs

  1. Ben says:

    Hi Brad – how would you call the close function and then redirect the browser to a url? We’re displaying tags in one of these dialogs and when the user clicks on tagged content we want it to close the dialog box and take them to that URL… 🙂

  2. Brad Saide says:

    Hi Ben.

    In the function feedbackReceived, add a second line that redirects the window to whatever location you want using window.location. So for example, if you wanted them to go to Google on Submit and Bing on Cancel, I think you would set it up something like this:

    function feedbackReceived(dialogResult, returnValue) {
    if(dialogResult == SP.UI.DialogResult.OK) {
    SP.UI.Notify.addNotification(‘Feedback Submitted!’);
    window.location=”http://www.google.com”;
    }

    else {
    SP.UI.Notify.addNotification(‘Feedback Cancelled…’);
    window.location=”http://www.bing.com”;
    }
    }

    Hope this helps…

  3. Matt Engel says:

    Hi Brad,

    Excellent post! I’m testing your solution now with a similar issue. I have two scenarios that I am working on that involve the use of the Dialog screen. I inherited an obscure list that has multiple forms running from it. I can get the default form to pull through normally but the other form pages are another story. The other situation is to have a series of links to a number of static pages that lists vendors by category. Each link will open a nice dialog box with the information.

    I’ll le you know how it goes and share any modifications that I may make to help out with this as well.

    Thanks for the post!

  4. Suresh Gupta says:

    Hi,
    In my case the current url does not populate in the text box.
    Not sure whats wrong.
    I am putting both the java scripts in my master page as the feedback is to be available from every page of the webapp.
    Can you please let me know.

    Thanks in advance.!

    • Brad Saide says:

      Hi Suresh – Note the solution only works for Internet Explorer. If you have a quick look around you’ll be able to find something similar that is cross-browser (I think in the comments of the article this links to, someone posted some more compatible code?)

  5. Mark Conger says:

    The Download Link doens’t appear to work any longer. Any chance we could get it fixed?

  6. Angela says:

    Hi
    Great post thanks – works perfecly when launched from a page in the same site collection as the feed back list.
    My problem is that when I launch it from a page in a different site collection it will open the dialog and will save any entries correctly however the dialog box won’t close on either Save or Cancel (the notification also doesn’t show but that doesn’t concern me in this case). I’ve dabbled with some other similar options for this launching the dialog box in various ways and have the same issue in each case I’ve tried.

    Any suggestions?
    thanks

    • Brad Saide says:

      Hi Angela.

      Sorry, I’ve only tried it from within the same site collection – It looks like you are not getting an event firing for the dialogReturnValueCallback. If the list item submission is working, maybe it’s worth rewriting the form using jQuery to “Save & Close” the buttons? I’m not sure what the answer is, but if you work out a way to do it, please let me know.

      Just out of interest, does the separate site collection have a separate Domain name? If it does, it will not work because it’ll be trying to breach the cross-site javascript boundary.

      • Angela says:

        Thanks for the quick reply Brad

        My javascript knowledge is pretty much nil but that explains alot. The other site collection i’d tried it with was in a separate web application with a different domain name so your answer clears that up.

        I just retried it in a different site collection under the same domain as the feedback list and it works fine there.

        You’ve saved me a lot of frustration in trying to make something work that shouldn’t anyway! Much appreciated

  7. Thomas H1709 says:

    Hi Brad,
    nice script, but I don’t get it to work because of the url for the new dialog isn’t exactly the same like yours…

    My URL is:
    http://servername/_layouts/listform.aspx?PageType=8&ListId=2F41C717-88C3-4945-BA04-45EADFE86F00&RootFolder=

    How do i implement the sourceDialog expression correctly?

    thanks in advance
    Thomas

    • Brad Saide says:

      Hmmmm, well I don’t have a lot to work with, but… remember all we are doing is popping the “new item” form from the feedback list… so what is the URL when you click “add new item” on the list you want the feedback to be stored in? If it opens in a lightbox, go into the list settings and change them so it opens in the same window (like it used to in SP 2010)… this will give you a working URL.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s