Returning Object from a Promise

HarveyEV picture HarveyEV · Aug 14, 2014 · Viewed 7.4k times · Source

I'm a bit new to using promises and am having an issue returning an object. I have the following function that calls SPServices to retrieve one item from a list. I know the SPService call is returning the list item, but the data returning is undefined:

$('.support-View').on('click', function () {
    var thisID = $(this).data("id");
    var message = getOneDetails(thisID);
    console.log("This Data  : " + message); //<-- Comes back undefined
    $.when(message).done(function() {
        thisMessage = message;
        viewRequestDialog(thisID, message);
    });
});

And the getOneDetails function looks like this:

function getOneDetails (thisID, viewtype) {

var CAML = '<Query><Where><Eq><FieldRef Name="Title" /><Value Type="Text">' + thisID + '</Value></Eq></Where></Query>';
var list = 'Support Requests';

var requestsPromise = $().SPServices.SPGetListItemsJson({
    listName: list,
    CAMLQuery: CAML,
    includeAllAttrs: true
});

$.when(requestsPromise).done(function() {
    requestData = this.data;
    console.log(this.data); //<---- Data is defined here

    })
    .then(function(requestData) {
    console.log(requestData); //<---- But undefined here
    return requestData;
}); 

}

Im sure I'm missing something simple, but how do I simply return the object from the promise function? TIA

Answer

Bergi picture Bergi · Aug 14, 2014

You never can return a value from a promise, because it might not yet have arrived. You only can return another promise, for a value that is computed from the result of the first promise. Your first snippet needs to look like this:

$('.support-View').on('click', function () {
    var thisID = $(this).data("id");
    var messagePromise = getOneDetails(thisID);
    messagePromise.done(function(message) {
        console.log("This Data  : " + message); // <-- Comes back as an argument
                                                //     to the callback
        // thisMessage = message; // Don't ever do this. Global variables are
                                  // useless when you don't know *when* they
                                  // will contain a value. If you need to store
                                  // something, store the `messagePromise`.
        viewRequestDialog(thisID, message);
    });
});

Your getOneDetails function needs to return a promise, it currently doesn't return anything. Why this.data is defined, but not passed as an argument to the callback I'm unsure; yet even when you did assign that to a global requestData variable that value will be shadowed by the local requestData variable (named parameter) of the then callback.

Ideally, it should look

return requestsPromise.then(function(requestData) { /*
^^^^^^ notice the return! */
    console.log(requestData); // <---- Data is given as an argument
    return requestData;
});

but you might need to do

return requestsPromise.then(function() { // again, return the result of the call
    var requestData = this.data; // take it from wherever (unsure what `this` is)
//  ^^^ local variable
    console.log(requestData); // <-- Data is defined here
    return requestData; // and can be returned to resolve the promise with
});