12

I'm using ng-show with an expression that resolves to a promise that resolves to a boolean. When I do this I get the 10 digest iterations overflow.

See http://plnkr.co/edit/XibYM0kCnXhKjNUeTsp3?p=preview

  <body ng-controller="MainCtrl">
    <p ng-show="returnsABoolean()">non promise</p>
    <p ng-show="returnsAPromiseThatResolvesToABoolean()">promise</p>
  </body>

Ctrl:

  $scope.returnsABoolean = ()->
    true

  $scope.returnsAPromiseThatResolvesToABoolean = ()->
    $q.when(false)

I know that {{somePromise}} will resolve, but {{returnsAPromiseThatResolvesToABoolean()}} seems to cause the same issue.

Any ideas? I'd expect this to work..

Roy Truelove
  • 22,016
  • 18
  • 111
  • 153

3 Answers3

7

AngularJS resolves the promise for template binding automatically. However, you should use the promise in ng-init to prevent the digest cycle from returning a new promise every tick.

<p ng-init="v=returnsAPromiseThatResolvesToABoolean()" ng-show="v">promise</p>
zs2020
  • 53,766
  • 29
  • 154
  • 219
  • 2
    According to the Angular 1.3 docs, this wouldn't be an appropriate use of ng-init: `The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.`, https://docs.angularjs.org/api/ng/directive/ngInit – Murphy Randle Oct 10 '14 at 14:03
5

Plunker: http://plnkr.co/edit/NvjP5qHafhyIWXXotBej?p=preview

This works as I think you intended it to. $q.when() returns a promise object, so ng-show is not getting a boolean value; it's getting a promise object.

Updated template:

  <body ng-controller="MainCtrl">
    <p ng-show="returnsABoolean()">non promise</p>
    <p ng-show="returnsAPromiseThatResolvesToABoolean">promise</p>
  </body>

Updated Ctrl:

  $scope.returnsABoolean = ()->
    true

  promise = $q.when(false)
  promise.then((val) ->
    $scope.returnsAPromiseThatResolvesToABoolean = val)
Roy Daniels
  • 6,309
  • 2
  • 27
  • 29
2

If you check out the sources here you 'll see that the promise is resolved in nextTick, so the $scope only changes the next time angular makes a $digest cycle. But your function returns a new promise on every $digest cycle, never actually getting the resolved value of the previous promise.

It's an old problem discussed here also.

You can overcome this issue by keeping a "persistent" reference to your promise outside the function as I did here.

Community
  • 1
  • 1
Sergiu Paraschiv
  • 9,929
  • 5
  • 36
  • 47