{"id":1004,"date":"2011-02-01T15:42:14","date_gmt":"2011-02-01T14:42:14","guid":{"rendered":"http:\/\/www.itidea.nl\/?p=1004"},"modified":"2015-09-08T20:33:34","modified_gmt":"2015-09-08T18:33:34","slug":"using-async-call-to-enable-a-custom-ribbon-button","status":"publish","type":"post","link":"https:\/\/www.itidea.nl\/index.php\/using-async-call-to-enable-a-custom-ribbon-button\/","title":{"rendered":"Using async call to enable a custom ribbon button"},"content":{"rendered":"<p>It is not always appropriate to enable custom buttons on the ribbon all the time. Sometimes one or multiple conditions have to be met to enable the button. As showed in one of my previous posts &#8216;<a href=\"https:\/\/www.itidea.nl\/index.php\/a-better-user-experience-with-the-dialog-framework-and-notifications\/\">A better user experience with the dialog framework and notifications<\/a>&#8216; the attribute EnabledScript of the CommandUIHandler can be used to test when to enable or disable the button. The check in\u00a0the example used in the previous post is quite simple and checks if one or more items are selected in the list.\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>To perform other, less simplistic, checks, it is likely you have to use asynchronous calls when working with ECMA script. Working with async calls in the ribbon is a bit different than working with synchronous calls and this is what this post is about.\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<h3>Functionality<\/h3>\n<p>Suppose you want to display a button on the ribbon on a default Tasks list. The Tasks list contains a column named Status. The button will only be enabled when exactly one item is selected in the list and when this selected item has a Status, a column\/field value, not equal to Completed.\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>The example will focus on the asynchronous part of the solution, not on creating a button on the ribbon.\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<h3>Solution<\/h3>\n<p>First of all a function is called from the EnabledScript attribute of CommandUIHandler.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;CommandUIHandler Command=&quot;TaskCompletedCommand&quot;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 CommandAction=&quot;javascript:alert('Not implemented.');&quot;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 EnabledScript=&quot;javascript:enableTaskNotCompletedButton();&quot;&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;\/CommandUIHandler&gt;\r\n<\/pre>\n<p>In this function a check is performed to make sure exactly one item is selected in the list.<br \/>\nAfter this check we have to get the Status field value of the selected item. Based on this value we enable or disable the button on the ribbon. When the Status field value is equal to Completed the button has to be disabled otherwise enabled. The return value of the function has to be false to disable a button, true to enable.<\/p>\n<p>The enableTaskNotCompletedButton function looks like this at the moment(will be adjusted during the post!):<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction enableTaskNotCompletedButton() {\r\n\u00a0\u00a0\u00a0 var result = false;\/\/default return value of the function which disables the button\r\n\u00a0\u00a0\u00a0 var selectedItems = SP.ListOperation.Selection.getSelectedItems();\r\n\u00a0\u00a0\u00a0 \/\/check if exactly one item is selected\r\n\u00a0\u00a0\u00a0 if (CountDictionary(selectedItems) == 1) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (this.itemId != selectedItems&#x5B;0]&#x5B;'id']) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 this.itemId = selectedItems&#x5B;0]&#x5B;'id'];\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GetTaskStatus(this.itemId);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else if (this.StatusValue == &quot;Completed&quot;) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 result = false; \/\/can be omitted, just for readibility\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 return result;\r\n}\r\n<\/pre>\n<p>To get the value of the Status field of the selected item an asynchronous call has to be made by the Client Object model. This call loads the value of the Status field in a variable so a check on this value can be performed.<br \/>\nSince this is an async call the ribbon doesn&#8217;t know when this function completes and is not going to wait for it to complete. Therefor you have to tell the ribbon explicitly that the async function is completed and that is has to come back to see if the button has to be enabled or disabled.<\/p>\n<p>Here the RefreshCommandUI method comes in which can be found in the Core.js. This function causes the Ribbon to refresh and EnableScript functions get called on the ribbon buttons.<br \/>\nBy calling this method the function in the EnabledScript attribute is called again.<\/p>\n<p>The following code is used for this example.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction GetTaskStatus(itemId) {\r\n\u00a0\u00a0\u00a0 var clientContext = SP.ClientContext.get_current();\r\n\u00a0\u00a0\u00a0 var currentList = clientContext.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());\r\n\u00a0\u00a0\u00a0 this.singleItem = currentList.getItemById(itemId);\r\n\u00a0\r\n\r\n\u00a0\u00a0\u00a0 clientContext.load(this.singleItem, 'Status');\r\n\u00a0\u00a0\u00a0 clientContext.executeQueryAsync(Function.createDelegate(this, this.OnSucceeded), Function.createDelegate(this, this.OnFailed));\r\n}\r\n\u00a0\r\n\r\nfunction OnSucceeded() {\r\n\u00a0\u00a0\u00a0 this.StatusValue = this.singleItem.get_item('Status');\r\n\u00a0\u00a0\u00a0 RefreshCommandUI();\r\n}\r\n\u00a0\r\n\r\nfunction OnFailed(sender, args) {\r\n\u00a0\u00a0\u00a0 alert('Error occurred: ' + args.get_message());\r\n}\r\n<\/pre>\n<p>\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>When programming the functions needed you have to keep in mind the function defined in EnabledScript fires twice.<br \/>\nThe first time it is the &#8216;initial time&#8217;, the second time is when calling the RefreshCommandUI method.\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>By keeping this in mind you have to keep track of a few things in the code, which can be used when it comes back on the second fire of the function.\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>The first item to keep track of is the item id. When selecting an item, deselecting and selecting the same item again, you don&#8217;t want the code to check the Status field value again, because you know that value already.<br \/>\nThe most important value you want to keep track of is the Status field value of the selected item. The first time the function fires and the async call is made the Status field value is stored. Then the RefreshCommandUI is called<br \/>\nand fires the function again. This is the time you want to know the previous set Status field value, because this is the time to return true or false to enable or disable the button.\u00a0\u00a0\u00a0\u00a0\u00a0<\/p>\n<p>With this knowledge the definite enableTaskNotCompletedButton function:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction enableTaskNotCompletedButton() {\r\n\u00a0\u00a0\u00a0 var result = false;\/\/default return value of the function which disables the button\r\n\u00a0\r\n\r\n\u00a0\u00a0\u00a0 var selectedItems = SP.ListOperation.Selection.getSelectedItems();\r\n\u00a0\u00a0\u00a0 \/\/check if exactly one item is selected\r\n\u00a0\u00a0\u00a0 if (CountDictionary(selectedItems) == 1) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (this.itemId != selectedItems&#x5B;0]&#x5B;'id']) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 this.itemId = selectedItems&#x5B;0]&#x5B;'id'];\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 GetTaskStatus(this.itemId);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else if (this.StatusValue == &quot;Completed&quot;) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 result = false; \/\/can be omitted, just for readibility\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/when RefreshCommandUI() makes the EnabledScript fire again, none of the above checks are valid\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/when the Status is not equal to Completed and the stored itemId is the same as the selected item id\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else if (this.StatusValue != &quot;Completed&quot; &amp;&amp; this.itemId == selectedItems&#x5B;0]&#x5B;'id']) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 result = true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\r\n\r\n\u00a0\u00a0\u00a0 return result;\r\n}\r\n<\/pre>\n<h3>Conclusion<\/h3>\n<p>When using async calls to check if a button has to be enabled in the ribbon you have to tell the ribbon when the async method is finished to check if the status of the button has to be updated.<br \/>\nThe RefreshCommandUI method helps you out with asynchronous calls. Besides this method a variable has to be set to keep track of the status(enable or disable) of the button.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It is not always appropriate to enable custom buttons on the ribbon all the time. Sometimes one or multiple conditions have to be met to enable the button. As showed in one of my previous posts &#8216;A better user experience &#8230; <a class=\"more-link\" href=\"https:\/\/www.itidea.nl\/index.php\/using-async-call-to-enable-a-custom-ribbon-button\/\">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":[42,6],"class_list":["post-1004","post","type-post","status-publish","format-standard","hentry","category-sharepoint-2010","tag-sharepoint-2010","tag-visual-studio"],"_links":{"self":[{"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/posts\/1004","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=1004"}],"version-history":[{"count":12,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/posts\/1004\/revisions"}],"predecessor-version":[{"id":1013,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/posts\/1004\/revisions\/1013"}],"wp:attachment":[{"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/media?parent=1004"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/categories?post=1004"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.itidea.nl\/index.php\/wp-json\/wp\/v2\/tags?post=1004"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}