22

I'd like to set up a promise and then throw it into a directive (using the databinding '=' attribute type) and do the then magic within the directive, but passing the promise as an attribute seems to result in the promise being resolved as undefined, so the then (and any other promise functionality) is unavailable.

Cebjyre
  • 6,552
  • 3
  • 32
  • 57

2 Answers2

16

I suspect this is due to this specific tweak:

$q promises are recognized by the templating engine in angular, which means that in templates you can treat promises attached to a scope as if they were the resulting values - angular $q docs

and this essentially results in the promise being converted within the template to the $$v value that the promise uses to store the resulting value, and at the linking stage this is likely to still be undefined - the converted value (ie undefined), not the promise itself is then passed into the directive.

The workaround is not to use the promise itself as the attribute passed into the directive, but to make it part of a parent object: the parent object won't have $q/template engine magic run, and so you'll be able to drill down into the promise from the parent and access then functionality from there.

See http://jsfiddle.net/cebjyre/95sjT/ for an example - uncommenting line 32 will cause a failure due to the top level promise no longer actually being a promise at that point, whereas the second level promise on line 17 works fine

Cebjyre
  • 6,552
  • 3
  • 32
  • 57
  • Thanks for that helpful answer. That's a pretty nasty wart on Angular though -- it handles binding to promises transparently directly in the view, but not in templates. So now even if you want to pass in straight data, you have to wrap it in a promise and a wrapper object. And now my directive template is full of ugliness like `{{itemList.promise[index]}}`. Directive just aren't as seamless as I would like. – Bennett McElwee Nov 05 '13 at 22:38
  • 6
    from angular 1.2 promises are no longer recognized by the templating engine – Oleg Belousov Dec 08 '13 at 12:49
6

Thanks. I have added this to Angular docs.

http://docs.angularjs.org/api/#comment-984109158

To achieve this wrap your promise in the parent: $scope.myDirectiveAtrribute = {promise: deferred.promise} and then in the directive access the promise

$scope.myDirectiveAtrribute.promise.then(function(){});

Ronan Rafferty
  • 189
  • 1
  • 9
  • I have also used this strategy using the Angular 1.5 components. I used angular.element(document).ready() and then accessed the promise from the ready callback. Probably a use case to stick with directives instead of components but it does work. – mbokil Feb 16 '16 at 16:56