3

I am busy with a piece of javascript which has problems working correctly. I am trying to work with a loop which contains an executeQueryAsync. When this one is executed it doesn't go straight to the function onQuerySucceeded, but still continues to go to the next one in the loop. In the onQuerySucceeded I got also an executeQueryAsync and this one also should be executed before the next item in the loop. Can someone help me to fix this problem. I've tried it with Promise and Deferred, but it doesn't work out that well.

    function doWork() { 

    ctx = new SP.ClientContext.get_current();
    var items = SP.ListOperation.Selection.getSelectedItems(ctx);

    if(items.length >= 1)
    {                                                                     
        for(idx in items)
        {
            var fixLinkPromise = fixLinkInAxapta(items[idx].id);
            fixLinkPromise.done(function(result) {
                console.log('It is done');
            });
            fixLinkPromise.fail(function(result) {
                console.log('It has failed');
            });                         
        }
    }

    alert('All items have been processed to Dynamics AX');
    window.location.href = window.location.href;
}

function fixLinkInAxapta(id) {

    dfd = $.Deferred();
    listId = SP.ListOperation.Selection.getSelectedList();
    listOrg = ctx.get_web().get_lists().getById(listId);

    web = ctx.get_web();                                        

    list = web.get_lists().getByTitle('AXDocuments');                                        

    var camlQuery = new SP.CamlQuery();
    camlQuery.set_viewXml('<View><RowLimit>100</RowLimit></View>');
    listItem = list.getItems(camlQuery);            
    item = listOrg.getItemById(id);
    props = web.get_allProperties();                                        

    ctx.load(web);
    ctx.load(listOrg);
    ctx.load(props);                                          
    ctx.load(listItem);
    ctx.load(item);

    ctx.executeQueryAsync(function() { dfd.resolve(onQuerySucceeded); },onQueryFailed); 

    return dfd.promise(); 
}   

function onQuerySucceeded() {
    var myProps = props;
    var myPropValues = myProps.get_fieldValues();
    var myValue = myPropValues['Props'];

    var xmlDoc = $.parseXML(myValue);
    if (xmlDoc) {
        var areaId = $(xmlDoc).find('Configuration').find('AreaId').text();

        for(var j = 0; j <= 6; j++)
        {
            var updateItem = listItem.itemAt(0);
            updateItem.set_item('DocumentIdentificationType', lookupValue);
            updateItem.update();
            ctx.executeQueryAsync(onUploadSucceeded, onQueryFailed);
        }
    }                          
}

function onUploadSucceeded()
{
    console.log('Upload succeeded');
}                         

function onQueryFailed(sender, args) {
    console.log(args);
}

I have got the solution and refactored my code to the following code

for(idx in items)
        {


            fixLinkInAxapta(items[idx].id).then(
                function (listItem, item, props) {
                    var myProps = props;
                    var myPropValues = myProps.get_fieldValues();
                    var myValue = myPropValues['myProps'];

                    var xmlDoc = $.parseXML(myValue);

                    if (xmlDoc) {                       
                        var areaId = $(xmlDoc).find('Configuration').find('AreaId').text();                                             

                        for(var j = 0; j <= 6; j++)
                        {
                            if (j === 0) {                              
                                var lookupField = item.get_item('LookupSoort');                             
                                var lookupValue = lookupField.get_lookupValue();                                                                                                            
                                var updateItem = listItem.itemAt(0);                                
                                updateItem.set_item('DocumentIdentificationType', lookupValue);                             
                                updateItem.set_item('DocumentIdentification1',item.get_item('AX_Nummer'));                              
                                updateItem.set_item('AreaId',areaId);
                                updateItem.set_item('DocumentUrl',item.get_item('EncodedAbsUrl'));                              
                                updateItem.update();

                                ctx.executeQueryAsync(onUploadSucceeded, onQueryFailed);

                            }
                            else {
                                var lookupFieldName = 'LookupSoort' + (j+1);
                                console.log(lookupFieldName);
                                var lookupField = item.get_item('LookupSoort' + (j + 1));
                                console.log(lookupField);
                                if(lookupField !== null)
                                {
                                    var updateItem = listItem.itemAt(0);                                        
                                    var lookupValue = lookupField.get_lookupValue();
                                    updateItem.set_item('DocumentIdentificationType', lookupValue);                                 
                                    updateItem.set_item('DocumentIdentification1',item.get_item('AX_Nummer' + (j + 1)));                                    
                                    updateItem.set_item('AreaId',areaId);
                                    updateItem.set_item('DocumentUrl',item.get_item('EncodedAbsUrl'));                                  
                                    updateItem.update();

                                    ctx.executeQueryAsync(onUploadSucceeded, onQueryFailed);
                                } 
                                else
                                {
                                    break;
                                }
                            }
                            if(j === 6) dfd.resolve();
                        }
                    }

                },
                function(sender, args) {

                });                
        }
2
 ctx.executeQueryAsync(function() { dfd.resolve(onQuerySucceeded); },onQueryFailed); 

Closely read what you are doing here:

You are (immediatly) resolving a Promise with a Function declaration,

Move that resolve to your onQuerySucceeded function with something like

 if (j===6) dfd.resolve();

Notes

  • I do not see proper var declaration of dfd, so if it is not hoisted to a parent scope it might not be available in your succeed function. If you are not reusing the succeed function then do not pollute the global scope and make it a local function inside the fixAxpta function.

  • Name your variables for what they are; your listItem is a Collection and not an item

  • quickly do away with those for loops and learn how about using the getEnumerator method on Collections

    function onQuerySucceeded() {
      var itemEnumerator = listItems.getEnumerator();
      while (itemEnumerator.moveNext()) {
       var item = listEnumerator.get_current();
      }
    }
    

    note; you would have to come up with another way to execute the resolvce after the last item.... ain't programming fun?

  • dfd.resolve() wasn't the total solution. It still passed by without hitting the onQuerySucceeded. – pipelinecache Apr 20 '16 at 7:03
  • So think like a computer and understand what function() { dfd.resolve(onQuerySucceeded); } does.. – Danny '365CSI' Engelman Apr 20 '16 at 7:29
0

The calls to SharePoint are async, so the loop will not wait for that, that's how async works.

Anyway, if you for some reason needs to have it synchronous you cannot use a normal for loop.

To make it synchronous you could use a function like this:

var asyncLoop = function(obj){
    var i=-1;

    var loop = function(){
        i++;
        if(i==obj.length){obj.callback(); return;}
        obj.functionToLoop(loop, i);
    } 
    loop();//init
}

And instead of your normal loop, do this:

asyncLoop({
    length : items.length,
    functionToLoop : function(loop, idx){

       var fixLinkPromise = fixLinkInAxapta(items[idx].id);
       fixLinkPromise.done(function(result) {
                console.log('It is done');
                loop();
            });
            fixLinkPromise.fail(function(result) {
                console.log('It has failed');
            });  

    },
    callback : function(){
        alert('All items have been processed to Dynamics AX');
        window.location.href = window.location.href;
    }    
});

I don't know your reasons, but I hardly can remember when I actually needed to do something synchronous.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.