{"id":745,"date":"2010-09-19T14:26:38","date_gmt":"2010-09-19T12:26:38","guid":{"rendered":"http:\/\/www.itidea.nl\/?p=745"},"modified":"2015-09-08T20:35:37","modified_gmt":"2015-09-08T18:35:37","slug":"a-better-user-experience-with-the-dialog-framework-and-notifications","status":"publish","type":"post","link":"https:\/\/www.itidea.nl\/index.php\/a-better-user-experience-with-the-dialog-framework-and-notifications\/","title":{"rendered":"A better user experience with the dialog framework and notifications"},"content":{"rendered":"<p>Today I am playing around with the dialog framework and simple ribbon buttons. I want the user to select one or more items from a list and update the Status field for all the items selected. The user can edit multiple items in datasheet view of course, but I\u2019m making it just a little friendlier to the user.<\/p>\n<p>I give myself two challenges for today:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>Add a button to the ribbon, enabling it when one or more items in the list are selected and update the Status field to \u2018Completed\u2019 of the selected items. This will be described at the paragraph \u2018Just the button\u2019 below.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>For more flexibility I will extend the above solution by a modal dialog where the user can choose a value for the Status column instead of setting the value to \u2018Completed\u2019 (and is not mentioned to the user anywhere), update the selected items and give the user a notification message if the update was successful and mentioning the Status value from the control on the modal dialog. This will be described at the paragraph \u2018Modal dialog\u2019 below.<\/p>\n<p>The last option will give the user a better experience and will be a lot more flexible, because I\u2019m not setting the value of the Status field in the code, but let the user choose from a predefined set of values.<\/p>\n<p>Not really challenges, but I just want to point out a few things which are maybe interested to you. I\u2019m not going to explain the basics of the ribbon or the dialog framework, because there are a lot of excellent posts out there.<\/p>\n<p>Just the button<br \/>\nAdd a button to the ribbon: please check out the cmdui.xml file located the SharePoint root folder, template\\global\\xml. Here you find a lot of definitions and examples you can use yourself and really helpful by positioning the controls on the ribbon.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>To just enable a button when one or more items in a list are selected is quite easy:<br \/>\nwhen defining a CustomAction with for example a button, you also define a CommandUIHandler. One of the attributes is EnabledScript:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nEnabledScript=&quot;javascript: function enableMarkAsCompletedButton(){\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var items = SP.ListOperation.Selection.getSelectedItems();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return (items.length &gt;= 1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 enableMarkAsCompletedButton();\u201d\r\n\r\n<\/pre>\n<p>Check the above code to enable the button (in this case) only when one or more items are selected. Here the client object model for ECMA script is used to get the selected items.<\/p>\n<p>Another attribute is CommandAction, the real action to occur when the button in the ribbon is clicked. The code used here:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nCommandAction=&quot;javascript:\r\n\u00a0\u00a0\u00a0 var context = SP.ClientContext.get_current();\r\n\u00a0\u00a0\u00a0 var currentList = context.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());\r\n\u00a0\u00a0\u00a0 var items = SP.ListOperation.Selection.getSelectedItems();\r\n\u00a0\u00a0\u00a0 var singleItem;\r\n\r\n\u00a0\u00a0\u00a0 for (var i in items) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 singleItem = currentList.getItemById(items&#x5B;i].id);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 singleItem.set_item('Status', 'Completed');\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 singleItem.update();\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\r\n\u00a0\u00a0\u00a0 \/\/actually submit\r\n\u00a0\u00a0\u00a0 context.executeQueryAsync(OnSuccess, OnError);\r\n\r\n\r\n\r\n\u00a0\u00a0\u00a0 function OnSuccess() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 window.location.href = window.location.href;\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\r\n\r\n\u00a0\u00a0\u00a0 function OnError(sender, args) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 alert('Error' + args.get_message());\r\n\r\n\u00a0\u00a0\u00a0 } &quot;\r\n<\/pre>\n<p>First grab the context and the list we\u2019re at. The getSelectedList() is the input of the getById() function. The result is the actual list where later the getItemById() function can be used on.<br \/>\nAlso check the for-loop. You can\u2019t use items[i].id directly in the getItemById() function on the list, but you have to grab the id of the single item and use this as the input parameter. Don\u2019t use the context.load() function, just execute the query asynchronously. The OnSuccess() function refreshes the page so the adjusted value can be seen and an alert is displayed when an error occurs.<\/p>\n<p>Modal dialog<br \/>\nBy using a modal dialog and give the result back to the user the user experience will be much better. I don\u2019t use a predefined value in the code but let the user choose which Status to set on all the selected items at once. Because I\u2019m using a dialog some additional text to explain the function and result better will be convenient for the user.<\/p>\n<p>For displaying a modal dialog the function SP.UI.ModalDialog.showModalDialog(options) will be used. The options I\u2019m going to use here are the url, width, height and the most important to explain here the dialogReturnValueCallback.<br \/>\nThe url is a custom page which will be opened. At the dialogReturnValueCallback a callback function will be specified, this means what is going to happen when the user closes the dialog. At our case the selected items in the list will be updated with the new status.<br \/>\nA lot of the above code can be reused at this scenario:<br \/>\nenabling the button when one or more list items are selected will not change at all.<br \/>\nupdating the list items will occur at a different moment, because we\u2019re going to display a dialog first to let the user choose the Status for the selected items.<\/p>\n<p>First let\u2019s look at the showModalDialog(options) and the page that will be opened at the url. I put the page at a subdirectory of the _layouts folder, so referencing is easy.<br \/>\nIn the page itself I put a dropdown control with some status values and a button to actually set the status. For better user experience I will list the selected items at the model dialog, so the user is still aware of what items are going to change. To list the items selected I will add the parameters listguid and the id\u2019s of the items selected to the url at the options for the showModalDialog function:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nvar options = {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 url: '\/_layouts\/ITIdea.DialogFramework\/PageSetStatus.aspx?listguid=' + SP.ListOperation.Selection.getSelectedList() + '&amp;amp;items=' + selectedItems,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 height : 600,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 width : 500,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dialogReturnValueCallback : CloseCallback};\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SP.UI.ModalDialog.showModalDialog(options);\r\n<\/pre>\n<p>And at the Page_Load function of the page I\u2019m getting the listguid and selected items and display it in a simple label control on the page (please do not use this code as production code!):<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 protected void Page_Load(object sender, EventArgs e)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (Request.QueryString&#x5B;&quot;listguid&quot;] != null &amp;&amp; Request.QueryString&#x5B;&quot;items&quot;] != null)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string list = Request.QueryString&#x5B;&quot;listguid&quot;].Substring(1, Request.QueryString&#x5B;&quot;listguid&quot;].Length - 2);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Guid listGuid = new Guid(list);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 List&lt;string&gt; selectedItems = new List&lt;string&gt;();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 selectedItems.AddRange(Request.QueryString&#x5B;&quot;items&quot;].Split(','));\r\n\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SPList selectedList = SPContext.Current.Web.Lists&#x5B;listGuid];\r\n\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string result = &quot;Selected items: &lt;br \/&gt;&quot;;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 foreach (string item in selectedItems)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 result += selectedList.GetItemById(int.Parse(item)).Title + &quot;&lt;br \/&gt;&quot;;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 selectedItemsText.InnerHtml = result;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n<\/pre>\n<p>And this is how is looks like in its simplest form:<br \/>\n<a href=\"https:\/\/www.itidea.nl\/wp-content\/uploads\/2010\/09\/ModalPage.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-747\" title=\"ModalPage\" src=\"https:\/\/www.itidea.nl\/wp-content\/uploads\/2010\/09\/ModalPage.png\" alt=\"\" width=\"190\" height=\"122\" \/><\/a><br \/>\nAfter the \u2018Set\u2019 button is selected the list items will be updated and for better user experience the user will be notified by a yellow notification on the right of the screen to what status the selected items are set. All this can be done at the function defined at dialogReturnValueCallback in the options of the showModalDialog, CloseCallback:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction CloseCallback(result, target) {\r\n\u00a0\u00a0\u00a0 if(result == SP.UI.DialogResult.OK){\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 SP.UI.Notify.addNotification('Status value is set to ' + target, true);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/set the status of all the selected items to the text\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 AdjustFields(target);\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 if(result == SP.UI.DialogResult.Cancel){\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 SP.UI.Notify.addNotification('Result is Cancel');\r\n\u00a0\u00a0\u00a0 }\r\n}\r\n\r\nfunction AdjustFields(newValue){\r\n\u00a0 var context = SP.ClientContext.get_current();\r\n\u00a0 var currentList = context.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());\r\n\u00a0 var items = SP.ListOperation.Selection.getSelectedItems();\r\n\u00a0 var singleItem;\r\n\u00a0 for (var i in items) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 singleItem = currentList.getItemById(items&#x5B;i].id);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 singleItem.set_item('Status', newValue);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 singleItem.update();\r\n\u00a0 }\r\n\r\n\r\n\u00a0 \/\/actually submit\r\n\u00a0 context.executeQueryAsync(OnSuccess, OnError);\r\n\r\n}\r\n\r\n\r\nfunction OnSuccess() {\r\n\u00a0\u00a0\u00a0 setTimeout(window.location.href = window.location.href, 3000);\r\n}\r\n\r\n\r\nfunction OnError(sender, args) {\r\n\u00a0\u00a0\u00a0 alert('Error' + args.get_message());\r\n}\r\n\r\n<\/pre>\n<p>The code for actually update the selected list items is moved to the AdjustFields function with newValue as input parameter and executed at the callback function of the dialog. This newValue is the value selected in the dropdown by the user at the modal dialog. How did we get that value over here?<br \/>\nHere another function of the SP.UI.ModalDialog comes in: commonModalDialogClose().<br \/>\nWith this function you can set your own return value which will be used at the callback function of the showModalDialog(). Real nice function!!<br \/>\nTo set a custom return value for the callback function, I use the commonModalDialogClose at the click eventhandler for the Set button at the page which is displayed as the modal dialog:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction SetNewStatus_Click() {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 var resultText = document.getElementById('StatusChoices').value;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, resultText);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n<\/pre>\n<p>In the above code the element \u2018StatusChoices\u2019 is the id of the dropdown control with the different status values. With the commonModalDialogClose() the dialog result is set to OK and the result value is set to the selected value in the dropdownbox.<br \/>\nBy setting the result to OK, the code in the CloseCallback() function will execute the code in the first if-statement. Here the message for the notification is set and the return value (target parameter, which was set at SetNewStatus_Click() ) is added to the notification message.<br \/>\n<a href=\"https:\/\/www.itidea.nl\/wp-content\/uploads\/2010\/09\/NotificationMessageStatusCompleted.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-746\" title=\"NotificationMessageStatusCompleted\" src=\"https:\/\/www.itidea.nl\/wp-content\/uploads\/2010\/09\/NotificationMessageStatusCompleted.png\" alt=\"\" width=\"236\" height=\"59\" \/><\/a>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>After explaining this simple example you\u2019re getting the idea of a better user experience with modal dialogs and notification messages. Inform the user as much as you can, the options are given to you by SharePoint and who are we not using them\u2026<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I am playing around with the dialog framework and simple ribbon buttons. I want the user to select one or more items from a list and update the Status field for all the items selected. The user can edit &#8230; <a class=\"more-link\" href=\"https:\/\/www.itidea.nl\/index.php\/a-better-user-experience-with-the-dialog-framework-and-notifications\/\">Read More &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[20,42,6],"class_list":["post-745","post","type-post","status-publish","format-standard","hentry","category-sharepoint-2010","tag-c","tag-sharepoint-2010","tag-visual-studio"],"_links":{"self":[{"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/posts\/745","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/comments?post=745"}],"version-history":[{"count":9,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/posts\/745\/revisions"}],"predecessor-version":[{"id":756,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/posts\/745\/revisions\/756"}],"wp:attachment":[{"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/media?parent=745"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/categories?post=745"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/tags?post=745"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}