{"id":243,"date":"2016-06-14T09:00:10","date_gmt":"2016-06-14T08:00:10","guid":{"rendered":"http:\/\/www.mysticslayer.com\/?p=243"},"modified":"2016-06-13T22:54:26","modified_gmt":"2016-06-13T21:54:26","slug":"sharepoint-javascript-from-asynchronous-to-synchronous-with-deferred-and-promise","status":"publish","type":"post","link":"http:\/\/www.mysticslayer.com\/?p=243","title":{"rendered":"SharePoint: Javascript from asynchronous to synchronous with Deferred and Promise"},"content":{"rendered":"<p>The last few years it has become more and more common that we use JavaScript for our SharePoint Projects. Whether it\u2019s Angular, Knockout or another preferred framework it\u2019s all very usable. But sometimes JavaScript can be a pain to use. For example, handling data in a synchronous way in Custom Actions. Recently I had to write code for sending document data to Dynamics AX. Since we use Business Connectivity Services to send the data to Dynamics AX and we are still using farm solutions I had to write a Custom Action.<br \/>\nWhen selecting multiple documents and handling the data in two for loops it\u2019s a pain, because if you are using variables in your class that must be used between functions it will be overwritten while your process is still running. Let\u2019s give a code example:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nvar ctx = '';\r\nvar web;\r\nvar list;\r\nvar listOrg;\r\nvar item;\r\nvar listItem;\r\nvar props;\r\nvar xmlDoc;\r\n\r\nfunction startWork() {\r\nctx = new SP.ClientContext.get_current();\r\n    \tvar items = SP.ListOperation.Selection.getSelectedItems(ctx);\r\n\tif (items.length &gt;= 1) {\r\n        \tfor (idx in items) {\r\n\t\t\tvar listId = SP.ListOperation.Selection.getSelectedList();\r\n    \t\t\tlistOrg = ctx.get_web().get_lists().getById(listId);\r\n\t\t\t\r\n    \t\t\tweb = ctx.get_web();\r\n\r\n    \t\t\tlist = web.get_lists().getByTitle('AX Documents');\r\n\r\n    \t\t\tvar camlQuery = new SP.CamlQuery();\r\n    \t\t\tcamlQuery.set_viewXml('&lt;View&gt;&lt;RowLimit&gt;100&lt;\/RowLimit&gt;&lt;\/View&gt;');\r\n    \t\t\tlistItem = list.getItems(camlQuery);\r\n    \t\t\titem = listOrg.getItemById(id);\r\n    \t\t\tprops = web.get_allProperties();\r\n\r\n    \t\t\tctx.load(web);\r\n    \t\t\tctx.load(listOrg);\r\n    \t\t\tctx.load(props);\r\n    \t\t\tctx.load(listItem);\r\n    \t\t\tctx.load(item, 'EncodedAbsUrl', 'AX_Nummer', 'AX_Nummer2', 'AX_Nummer3', 'AX_Nummer4', 'AX_Nummer', 'LookupSoort', 'LookupSoort2', 'LookupSoort3', 'LookupSoort4', 'LookupSoort5');\r\n\r\n    \t\t\tctx.executeQueryAsync(Function.createDelegate(this, onQuerySucceeded, Function.createDelegate(this, onQueryFailed));\r\n\r\n\t\t}\r\n\t}\r\n}\r\n\r\nFunction onQuerySucceeded() {\r\n\r\n\tvar myProps = props;\r\nvar myPropValues = myProps.get_fieldValues();\r\n\tvar myValue = myPropValues&#x5B;'Sil.AA.DMS.Common.Configurations'];\r\n\tvar xmlDoc = $.parseXML(myValue);\r\n\t\r\nif (xmlDoc) {\r\n\t\tvar areaId = $(xmlDoc).find('Configuration').find('AreaId').text();\r\n\r\n\t\tfor (var j = 0; j &lt;= 6; j++) {\r\n\t\t       if (j === 0) {\r\n\r\n\t\t\t\tvar lookupField = item.get_item('LookupSoort');\r\n\t\t\t       var lookupValue = lookupField.get_lookupValue();\r\n\t\t              var updateItem = listItem.itemAt(0);\r\n\t\t\t\tupdateItem.set_item('DocumentIdentificationType', lookupValue);\r\n\t\t\t\tupdateItem.set_item('DocumentIdentification1', item.get_item('AX_Nummer'));\r\n\t\t\t\tupdateItem.set_item('AreaId', areaId);\r\n\t\t\t\tupdateItem.set_item('DocumentUrl', item.get_item('EncodedAbsUrl'));\r\n\t\t\t\tupdateItem.update();\r\n\r\n\t\t\t\tctx.executeQueryAsync(onUploadSucceeded, onQueryFailed);\r\n\r\n}\r\n\t\t\telse {\r\n\t\t\t\tvar lookupFieldName = 'LookupSoort' + (j + 1);\r\n\t\t\t\tvar lookupField = item.get_item('LookupSoort' + (j + 1));\r\n\t\t\t\t\r\nif (lookupField !== null) {\r\n\t\t\t\t\tvar updateItem = listItem.itemAt(0);\r\n\t\t\t\t       var lookupValue = lookupField.get_lookupValue();\r\n\t\t\t\t       updateItem.set_item('DocumentIdentificationType', lookupValue);\r\n\t\t\t\t       updateItem.set_item('DocumentIdentification1', item.get_item('AX_Nummer' + (j + 1)));\r\n\t\t\t\t       updateItem.set_item('AreaId', areaId);\r\n\t\t\t\t       updateItem.set_item('DocumentUrl', item.get_item('EncodedAbsUrl'));\r\n\t\t\t\t       updateItem.update();\r\n\r\n\t\t\t\t       ctx.executeQueryAsync(onUploadSucceeded, onQueryFailed);\r\n\t\t\t        }\r\n\t\t\t\r\n\t              }\r\n\t      }\r\n\t}\r\n}\r\n\r\nFunction onUploadSucceeded() {\r\n\tAlert(\u2018File has been processed\u2019);\r\n}\r\n\r\nFunction onQueryFailed(sender, args) {\r\n\tAlert(\u2018File not processed: \u2018 + args);\r\n}\r\n<\/pre>\n<p>Let\u2019s say I run the above code with two items, it will see both items, but the processing will be asynchronous. Since executeQueryAsync will be run the first time, but the first for loop will be processed at the same time. I have two items:<\/p>\n<table width=\"1309\">\n<tbody>\n<tr>\n<td width=\"257\">FileLeafReg<\/td>\n<td width=\"78\">Title<\/td>\n<td width=\"90\">AX_Number<\/td>\n<td width=\"92\">LookupSoort<\/td>\n<td width=\"97\">AX_Number2<\/td>\n<td width=\"99\">LookupSoort2<\/td>\n<td width=\"97\">AX_Number3<\/td>\n<td width=\"99\">LookupSoort3<\/td>\n<td width=\"99\">AX_Number4<\/td>\n<td width=\"99\">LookupSoort4<\/td>\n<td width=\"99\">AX_Number5<\/td>\n<td width=\"99\">LookupSoort5<\/td>\n<\/tr>\n<tr>\n<td width=\"257\"><a href=\"http:\/\/sp2013\/Documents\/picture1.png\">http:\/\/sp2013\/Documents\/picture1.png<\/a><\/td>\n<td width=\"78\">Picture 1<\/td>\n<td width=\"90\">VN12345<\/td>\n<td width=\"92\">Sales<\/td>\n<td width=\"97\">VN12346<\/td>\n<td width=\"99\">Sales<\/td>\n<td width=\"97\">VN12347<\/td>\n<td width=\"99\">Sales<\/td>\n<td width=\"99\">Null<\/td>\n<td width=\"99\">Null<\/td>\n<td width=\"99\">Null<\/td>\n<td width=\"99\">Null<\/td>\n<\/tr>\n<tr>\n<td width=\"257\"><a href=\"http:\/\/sp2013\/Documents\/picture2.png\">http:\/\/sp2013\/Documents\/picture2.png<\/a><\/td>\n<td width=\"78\">Picture 2<\/td>\n<td width=\"90\">VN67890<\/td>\n<td width=\"92\">Sales<\/td>\n<td width=\"97\">VN67891<\/td>\n<td width=\"99\">Sales<\/td>\n<td width=\"97\">Null<\/td>\n<td width=\"99\">Null<\/td>\n<td width=\"99\">Null<\/td>\n<td width=\"99\">Null<\/td>\n<td width=\"99\">Null<\/td>\n<td width=\"99\">Null<\/td>\n<\/tr>\n<tr>\n<td width=\"257\">&nbsp;<\/td>\n<td width=\"78\">&nbsp;<\/td>\n<td width=\"90\">&nbsp;<\/td>\n<td width=\"92\">&nbsp;<\/td>\n<td width=\"97\">&nbsp;<\/td>\n<td width=\"99\">&nbsp;<\/td>\n<td width=\"97\">&nbsp;<\/td>\n<td width=\"99\">&nbsp;<\/td>\n<td width=\"99\">&nbsp;<\/td>\n<td width=\"99\">&nbsp;<\/td>\n<td width=\"99\">&nbsp;<\/td>\n<td width=\"99\">&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>It will result in processing the second items 5 times, with the properties of the second file. Because the for loop will put the values of the second file over the variables of the first file, since the first for loop is faster in processing. And the onQuerySucceeded will only be processed when the first for loop is done. So it will break every piece of code in the chain.<br \/>\nI talked with several people, experts in JavaScript and even on StackOverflow, and I never got a decent answer how to fix it properly. It always resulted that the chain was broken. I tried promise and deferred in different manners, still not as it should be. I was getting headaches because of it, since none of the answers sufficed in a proper way.<br \/>\nNormally I am absolutely not a morning person, and the breakthroughs are normally at night when everybody is asleep. But two weeks ago, when it was still very early in the morning I woke up and started to code, just before driving to the office, I found my answer in a way that I could live with it.<br \/>\nI shuffled and refactored all my notepad++ tabs in one singular tab and there it was. A solution that was clear to read. Let\u2019s go through the promise and deferred part. The steps are marked in Red from Step 1 \u2018till 6. So that the code is easy to follow.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nvar ctx = '';\r\n\r\nfunction startWork() {\r\nctx = new SP.ClientContext.get_current();\r\nvar items = SP.ListOperation.Selection.getSelectedItems(ctx);\r\n   \tif (items.length &gt;= 1) {\r\n       \t for (idx in items) {\r\n\t\t\tfixLinkInAxapta(items&#x5B;idx].id).then(\t\/\/ Step 1: Instead of running the first clientContext executeQueryAsync. We first go into the function and prepare the Promise\r\n\t\t\t\tfunction (listItem, item, props) { \/\/ Step 4: is running this in synchronous mode.\r\n\t\t\t\t\tvar myProps = props;\r\n\t\t\t\t    \tvar myPropValues = myProps.get_fieldValues();\r\n\t\t\t\t    \tvar myValue = myPropValues&#x5B;'Sil.AA.DMS.Common.Configurations'];\r\n\t\t\t\t    \tvar xmlDoc = $.parseXML(myValue);\r\n\t\t\t\t    \tif (xmlDoc) {\r\n\t\t\t\t        \tvar areaId = $(xmlDoc).find('Configuration').find('AreaId').text();\r\n\t\t\t\t\t\tfor (var j = 0; j &lt;= 6; j++) {\r\n\t\t\t\t            if (j === 0) {\r\n\t\t\t\t                var lookupField = item.get_item('LookupSoort');\r\n\t\t\t\t                var lookupValue = lookupField.get_lookupValue();\r\n\t\t\t\t                var updateItem = listItem.itemAt(0);\r\n\t\t\t\t                updateItem.set_item('DocumentIdentificationType', lookupValue);\r\n\t\t\t\t                updateItem.set_item('DocumentIdentification1', item.get_item('AX_Nummer'));\r\n\t\t\t\t                updateItem.set_item('AreaId', areaId);\r\n\t\t\t\t                updateItem.set_item('DocumentUrl', item.get_item('EncodedAbsUrl'));\r\n\t\t\t\t                updateItem.update();\r\n\r\n\t\t\t\t                ctx.executeQueryAsync(onUploadSucceeded, onQueryFailed);\r\n\r\n\t\t\t\t            }\r\n\t\t\t\t            else {\r\n\t\t\t\t                var lookupFieldName = 'LookupSoort' + (j + 1);\r\n\t\t\t\t                var lookupField = item.get_item('LookupSoort' + (j + 1));\r\n\t\t\t\t                if (lookupField !== null) {\r\n\t\t\t\t                    var updateItem = listItem.itemAt(0);\r\n\t\t\t\t                    var lookupValue = lookupField.get_lookupValue();\r\n\t\t\t\t                    updateItem.set_item('DocumentIdentificationType', lookupValue);\r\n\t\t\t\t                    updateItem.set_item('DocumentIdentification1', item.get_item('AX_Nummer' + (j + 1)));\r\n\t\t\t\t                    updateItem.set_item('AreaId', areaId);\r\n\t\t\t\t                    updateItem.set_item('DocumentUrl', item.get_item('EncodedAbsUrl'));\r\n\t\t\t\t                    updateItem.update();\r\n\r\n\t\t\t\t                    ctx.executeQueryAsync(onUploadSucceeded, onQueryFailed);\r\n\t\t\t\t                }\r\n\t\t\t\t                else {\r\n\t\t\t\t                    break;\r\n\t\t\t\t                }\r\n\t\t\t\t            }\r\n\t\t\t\t            if (j === 6) dfd.resolve(); \/\/ Step 5: Resolve the Deferred\r\n\t\t\t\t        }\r\n\t\t\t\t    }\r\n\r\n\t\t\t\t},\r\n\t\t\t\tfunction (sender, args) {\r\n\r\n\t\t\t\t});\r\n        }\r\n    }\r\n\r\n    alert('All items have been processed to Dynamics AX');\r\n}\r\nfunction fixLinkInAxapta(id) {\r\n    var dfd = $.Deferred(); \/\/ Step 2: Setup the Deferred method\r\n    var listId = SP.ListOperation.Selection.getSelectedList();\r\n    var listOrg = ctx.get_web().get_lists().getById(listId);\r\n    var item;\r\n    var props;\r\n    var list;\r\n    var listItem;\r\n    var web;\r\n\r\n    web = ctx.get_web();\r\n\r\n    list = web.get_lists().getByTitle('AX Documents');\r\n\r\n    var camlQuery = new SP.CamlQuery();\r\n    camlQuery.set_viewXml('&lt;View&gt;&lt;RowLimit&gt;1&lt;\/RowLimit&gt;&lt;\/View&gt;');\r\n    listItem = list.getItems(camlQuery);\r\n    item = listOrg.getItemById(id);\r\n    props = web.get_allProperties();\r\n\r\n    ctx.load(web);\r\n    ctx.load(listOrg);\r\n    ctx.load(props);\r\n    ctx.load(listItem);\r\n    ctx.load(item, 'EncodedAbsUrl', 'AX_Nummer', 'AX_Nummer2', 'AX_Nummer3', 'AX_Nummer4', 'AX_Nummer', 'LookupSoort', 'LookupSoort2', 'LookupSoort3', 'LookupSoort4', 'LookupSoort5');\r\n\/\/ Step 3: Resolve the listItem, item and the properties and call the function(listItem, item, props) in the previous method and wait for it to finish. If an error occurs go to reject\r\n    ctx.executeQueryAsync(Function.createDelegate(this, function () { dfd.resolve(listItem, item, props); }), Function.createDelegate(this, function (sender, args) { dfd.reject(sender, args); }));\r\n\r\n    return dfd.promise(); \/\/ Step 6: When the ClientContext.executeQueryAsync is resolved make it promise and return to the For Loop\r\n}\r\n\r\n<\/pre>\n<p>Of course if you have any questions, don\u2019t hesitate to comment on this blogpost and I will get back to you as soon as possible. More blog posts will follow soon.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The last few years it has become more and more common that we use JavaScript for our SharePoint Projects. Whether it\u2019s Angular, Knockout or another preferred framework it\u2019s all very usable. But sometimes JavaScript can be a pain to use. For example, handling data in a synchronous way in Custom Actions. Recently I had to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[3,369,368],"tags":[373,372,370,375,371,52,374],"class_list":["post-243","post","type-post","status-publish","format-standard","hentry","category-blog","category-javascript","category-sharepoint","tag-asynchronous","tag-deferred","tag-javascript","tag-jquery","tag-promise","tag-sharepoint","tag-synchronous"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pe1EH-3V","_links":{"self":[{"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=\/wp\/v2\/posts\/243","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=243"}],"version-history":[{"count":3,"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=\/wp\/v2\/posts\/243\/revisions"}],"predecessor-version":[{"id":251,"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=\/wp\/v2\/posts\/243\/revisions\/251"}],"wp:attachment":[{"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=243"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.mysticslayer.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}