Resolve promise with an object with a "then" function

angularjs, promise

Solution

Solution

The `then` property that you're passing in is overriding the promise's `then` property. You instead want to return your object from within the success callback of the angular promises `then` function like this:

$scope.resolvePromise2 = function() {
    deferred2.resolve({
      then: function(successCB) {
        successCB({myResult1:'result1',
                  myResult2:'result2',
                  'then':function() {console.log("got here")}});
      }
    });
  };

Using the above your message is now called and you can call the `then` function in your property:

promise2.then(function(result) {
   //Now we get here
   $scope.messages2.push('Promise 2 then callback. Result is:' + result);
   result.then();
});

Here's your updated working plunker.

Issue/Why this works

Let's look at the Angular `resolve()`:

resolve: function(val) {
    if (pending) {
      var callbacks = pending;
      pending = undefined;
      value = ref(val);

      if (callbacks.length) {
        nextTick(function() {
          var callback;
          for (var i = 0, ii = callbacks.length; i < ii; i++) {
            callback = callbacks[i];
            value.then(callback[0], callback[1], callback[2]);
          }
        });
      }
    }
  },

Looking at `value = ref(val);` followed by `value.then(callback[0], callback[1], callback[2]);` we see that Angular attaches the `then` function to the promise as a property and that the object you passed in overrides that property. So, in your case, the passed in `then` function is called instead of `deferred.promise.then(function(result)...`.

But Angular calls your `then` function with the three callbacks (success, error, notify): `value.then(callback[0], callback[1], callback[2]);` that were saved off in `var callbacks = pending;`

So the solution is to call the first "success" callback inside your `then` function and pass it your object including the `then` property you want returned. Now the promise's `then` is called and receives your object including your `then` property

then: function(successCB) {
   successCB({myResult1:'result1',
              myResult2:'result2',
              'then':function() {console.log("got here")}});
}

Problem

This is a bit of an abstract question, as I don't have a particular use-case right now. I've noticed that if you resolve a promise with a promise ``` var deferredA = $q.defer(); var deferredB = $q.defer(); deferredA.promise.then(function(result) { // Will get here once promiseB has been resolved. }); deferredA.resolve(deferredB.promise); ``` than promiseA isn't actually resolved until promiseB has been resolved (and then promiseA is resolved with the value of promiseB's resolution). However, what if I wanted to resolve with a value of an object with a "then" function, as: ``` var deferred = $q.defer(); deferred.promise.then(function(result) { // Aim is to get here with result = {then:function(){}}, // as though I had resolved a promise with a non-promise value, // but this function is never called }); deferred.resolve({ then: function() { } }); ``` then promiseA never actually gets resolved, as it assumed that the value is a promise, even though in the above example it's not, as in, it wasn't created with $q.defer(). There is an example plunkr at http://plnkr.co/edit/Z8XUKzxHtGBKBmgPed2q?p=preview Is there a way around this? If so, how? Edit: clarified deferred/promise & put in example "then" callbacks.

Original source