methuselah
methuselah

Reputation: 13216

Cannot read property 'then' of undefined when returning nested promise

I keep getting the following error: TypeError: Cannot read property 'then' of undefined, in checkInventoryData. How can I resolve it?

function checkInventoryData(url, size, code) {
  var inventoryData = { };

  return $http.get(url).then(function(response) {
    var html = response.data;

    // getting error here: TypeError: Cannot read property 'then' of undefined
    getInventoryProductQty(html, size).then(function(result) {
        result = inventoryData.productQty;
    });

    return inventoryData;
  });
}

function getInventoryProductQty(html, size) {
  var inventoryAvailable;
  var deferred = $q.defer();
  try {
    var inventoryAvailablity = getInventoryAvailability(html, size);
    inventoryAvailablity.then(function(result) {
      if(result) {
        inventoryAvailable = result.getAttribute('data-available');
        deferred.resolve(inventoryAvailable);
        return deferred.promise;
      }
    });
  }
  catch(err) {
    inventoryAvailable = null;
    return inventoryAvailable;
  }
}

Upvotes: 0

Views: 1046

Answers (3)

ValLeNain
ValLeNain

Reputation: 2314

What you're doing for now, inside getInventoryProductQty

inventoryAvailablity.then(function(result) {
      if(result) {
        inventoryAvailable = result.getAttribute('data-available');
        deferred.resolve(inventoryAvailable);
        return deferred.promise;
      }
    });

This is not a return statement and so your function does not return anything.
If what you would like to return is inventoryAvailable (once it has been retrieved), you would do something like

return inventoryAvailablity.then(function(result) {
  if(result) {
    inventoryAvailable = result.getAttribute('data-available');
    return inventoryAvailable;
  } else {
    /* reject ? */
  }
});

[edit]
I would actually rewrite the function this way

function getInventoryProductQty(html, size) {
  var inventoryAvailable;
  try {
    var inventoryAvailablity = getInventoryAvailability(html, size);
    return inventoryAvailablity.then(function(result) {
      if(result) {
        inventoryAvailable = result.getAttribute('data-available');
        return inventoryAvailable;
      } else {
        /* reject ? */
      }
    });
  }
  catch(err) {
    return $q.reject(err);
  }
}

Upvotes: 1

trincot
trincot

Reputation: 351403

Once you rely on a promise, you need to make sure to keep returning promises in the call chain.

Here is the suggested code:

function checkInventoryData(url, size, code) {
  // Warning: code is nowhere used!
  // Return(!) the promise:
  return $http.get(url).then(function(response) {
    var html = response.data;
    return getInventoryProductQty(html, size);
  });
}

function getInventoryProductQty(html, size) {
  try {
    // return the result of `then`, which is a promise:
    return getInventoryAvailability(html, size).then(function(result) {
      if(result) {
        // Just return the value. No need to return a promise.
        // I assume you have a productQty property here:
        return result.getAttribute('data-available').productQty;
      } else { // also deal with the failure:
        throw "no result from getInventoryAvailability";
      }
    });
  }
  catch(err) {
    // return a failed promise here:
    return $q.reject(err);
  }
}

Don't expect checkInventoryData to synchronously return the value. It is also a promise, and you need to apply then to it to get the promised value in a callback function. Also make sure to use a catch method whenever you call checkInventoryData, so you can deal with errors.

Upvotes: 1

Jim Deville
Jim Deville

Reputation: 10672

You need to return a promise from getInventoryProductQty, right now you return null in the error case, but nothing in the normal case (and neither of those are promises.

EDIT - showing this answer in OPs code, and comment on the structure.

function checkInventoryData(url, size, code) {
  var inventoryData = { };

  return $http.get(url).then(function(response) {
    var html = response.data;

    // getting error here: TypeError: Cannot read property 'then' of undefined
    getInventoryProductQty(html, size).then(function(result) {
        result = inventoryData.productQty; // this has not been set at this point, you need to set it somehow (@trincot's comment)
    });

    return inventoryData;
  });
}

function getInventoryProductQty(html, size) {
  var inventoryAvailable;
  var deferred = $q.defer();
  try {
    var inventoryAvailablity = getInventoryAvailability(html, size);
    return inventoryAvailablity.then(function(result) { // need to add this return to return the result of the then func
      if(result) {
        inventoryAvailable = result.getAttribute('data-available');
        deferred.resolve(inventoryAvailable);
        return deferred.promise;
      }
    });
  }
  catch(err) {
    //inventoryAvailable = null;
    //return inventoryAvailable;
    return $q.resolve(null); // need something like this to return a promise from the failure case
  }
}

You also should make getInventoryAvailability return a promise so that it can be called with a .catch instead of a try...catch, but that's beyond the scope of this

Upvotes: 1

Related Questions