Question

I'm pulling information from an Excel spreadsheet and trying to check the rows against data from a SharePoint list to find duplicates.

The executeQueryAsync() in the itemIsDuplicate() function is causing the promise to try to resolve before the promise is returned resulting in the error message "Unable to get property 'then' of undefined or null reference"

Here are the relevant sections of code:

 for (var i = 0; i < rows.length; i++) {               
            var newItem = {
                week: rows[i].Week._Default,
                customer: rows[i].Customer._Default,
                resource: rows[i].Resource,
                title: rows[i].Title._Default,
                category: rows[i].Category._Default,
                notes: rows[i].Notes._Default,
                plannedHours: rows[i].PlannedHours._Default,
                percentComplete: rows[i].PercentComplete._Default,
                extID: rows[i].ExtID._Default,
                actualHours: rows[i].ActualHours._Default,
                type: rows[i].Type._Default,
                dmRequest: rows[i].DMRequest._Default
            }

            itemIsDuplicate(newItem).then(function (isDuplicate) {
                if (!isDuplicate) {
                    newItems.push(newItem);
                }

                else {
                    duplicates.push(newItem);
                }

            })
        }

        $.when.apply($, promises).done(function () {
            //process results...
        } 

function itemIsDuplicate(item, newItems) {

            var deferred = new $.Deferred();
            promises.push(deferred);
            var isDuplicate = false;
            var duplicateQuery = new SP.CamlQuery();
            duplicateQuery.set_viewXml(
                '<View><Query><Where>' +
                    '<And>'+
                        '<Eq>' +
                            '<FieldRef Name= \'Week\' />' +
                            '<Value Type= \'DateTime\' IncludeTimeValue=\'FALSE\'>' + new Date(item.week).toISOString() + '</Value>' +
                        '</Eq>' +
                        '<And>' +
                            '<Eq>' +
                                '<FieldRef Name= \'LIS_x0020_Analyst\' />' +
                                '<Value Type= \'Text\'>' + item.resource + '</Value>' +
                            '</Eq>' +
                            '<Eq>' +
                                '<FieldRef Name= \'Title\' />' +
                                '<Value Type= \'Text\'>' + item.title + '</Value>' +
                            '</Eq>' +                          
                        '</And>' +
                    '</And>' +
                '</Where></Query></View>'
            )

            var duplicateItemsColl = worklist.getItems(duplicateQuery);
            clientContext.load(duplicateItemsColl);
            clientContext.executeQueryAsync(
                function () {
                    if (duplicateItemsColl.get_count() > 0) {
                        isDuplicate = true;
                    }

                    deferred.resolve(isDuplicate);
                    return deferred.promise();
                },    
                function (sender, args) {

                    console.log("Error message here...")
                }
            );                     
        }

Does anybody have a good solution to avoid this problem?

I'm pretty new to JavaScript development in SharePoint, and the use of $.Deferred, so this might be simple but the answer has eluded me so far. Thanks.

Was it helpful?

Solution

You need to return the promise in the itemIsDuplicate() function, not the success callback. Just move return deferred.promise(); to the end of the function. You'll might want to either add deferred.resolve() to the error callback, or a deferred.reject() if you need to execute something after an error occurs.

Code should be as such:

function itemIsDuplicate(item, newItems) {
    var deferred = $.Deferred(),
        isDuplicate = false,
        duplicateQuery = new SP.CamlQuery();

    duplicateQuery.set_viewXml( '<your caml query>' );

    duplicateItemsColl = worklist.getItems(duplicateQuery);
    clientContext.load(duplicateItemsColl);
    clientContext.executeQueryAsync(
        function(){ deferred.resolve(duplicateItemsColl.get_count() > 0); },
        function(sender, args) { deferred.reject(sender, args.get_message()); }
    );
    return deferred.promise();
}

And whenever you call it:

var checkDuplicate = itemIsDuplicate(newItem);
promises.push(checkDuplicate);
checkDuplicate
    .done(function(isDuplicate) {
        if(!isDuplicate) newItems.push(newItem);
        else duplicates.push(newItem);
    })
    .fail(function(sender, error) {
        console.error(sender, error);
    });
$.when.apply($, promises).done(function () {
    //process results...
} 
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top