5

Angular's $q documentation says "$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's view templates also let you evaluate expressions, which means you can call functions exposed from the scope.

I've found that a view template is able to refer to real values, promises (which eventually resolve to real values), or functions returning real values, but not functions returning promises, which always render {} into the view template.

I created a fiddle with an example of this.

Can anyone do better or steer me in the right direction?

(Perhaps using a function in the view template is a bad idea; there are other problems with this technique, because Angular watching a function can't tell whether it's changed without calling the function, so the watched function gets evaluated on every digest cycle. I've seen these two questions and in both of them, the recommended answer was to use promise.then to change a normal property on the scope, and have the view template watch the normal property instead of the promise. I get that, but for my use I want to supply some parameters to calculate a value, and it's convenient to supply those parameters directly in the view template. Basically I'm trying to write something like url_for in Flask or Rails.)

Community
  • 1
  • 1
metamatt
  • 13,809
  • 7
  • 46
  • 56

2 Answers2

2

I'm not exactly sure, but if you return an object with the promise as a property, it works. (fiddle)

var deferred2 = $q.defer();
$scope.po = { promise: deferred2.promise };
$scope.getPo = function() {
    return $scope.po;
};

$timeout(function() {
    deferred2.resolve('some lazy text');
}, 2000);

HTML:

<p>Function returning promise (object): {{ getPo().promise }}</p>
Jason Goemaat
  • 28,692
  • 15
  • 86
  • 113
  • Yup, works for me. When I have more time I'll try to dig into the source and figure out why, and whether it's a bug worthy of reporting that the raw promise returned from a function doesn't work. This is a useful trick, though. – metamatt Oct 25 '13 at 20:14
0

A promise represents a future value, usually a future result of an asynchronous operation, and allows us to define what will happen once this value becomes available, or when an error occurs.

Reference

var promise = asyncFunction(parameters); 

promise.then( 
 function (result) { 
 // Do Something with the result 
 }, 
 function (error) { 
 // Handle error (exception, etc). 
 }); 

You can wrap any value with a promise, using the utility method $q.when().

  • $q.when(promise) → promise
  • $q.when(nonPromise) → a new promise, that will
  • asynchronously resolve to the given value nonPromise.

==============================

In your example:

HTML

<div ng-app ng-controller="testController">
    <p>Direct property: {{ property }}</p>
    <p>Function returning property: {{ getProperty() }}</p>
    <p>Direct promise: {{ promise }}</p>
    <p>Function returning promise: {{ out }}</p>
</div>

JS

function testController($scope, $q) {
    var deferred = $q.defer();
    deferred.resolve('some lazy text');
    $scope.promise = deferred.promise;

    $scope.out = $scope.promise.then(function (result) {
        console.log(result);
        return result;
    });


    $scope.property = 'some text';
    $scope.getProperty = function () {
        return $scope.property;
    };
}

Demo Fiddle

Maxim Shoustin
  • 77,483
  • 27
  • 203
  • 225
  • Thanks, but that doesn't answer my question (or it's the same answer as the prior questions that I linked to). You're no longer calling the function from the template, so, for example, if getProperty() took parameters, I can't supply them from the template. – metamatt Oct 23 '13 at 23:01
  • (I agree your solution works, and given the way watches evaluate functions in watched expressions every digest cycle, perhaps it's for the best to avoid use of function calls in view templates. However, I would like to understand why Angular can handle function calls and promises in template expressions but not together.) – metamatt Oct 23 '13 at 23:02
  • Generally I would put `promise` logic into service (Singleton) and use it as utility – Maxim Shoustin Oct 24 '13 at 04:52
  • Automatic unwrapping of promises does no more work in Angular >= 1.2.0 - see discussions in [#4158](https://github.com/angular/angular.js/issues/4158), [#4270](https://github.com/angular/angular.js/pull/4270) and [#5153](https://github.com/angular/angular.js/issues/5153) – hupf Dec 03 '13 at 08:26