10

AngularJS docs say:

$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.

So could someone please explain the reason this fiddle not working? It's not possible to change text field value. But assigning promises that $http service returns to a scope field works like a charm.

Controller:

function MyController($scope, $q, $timeout) {
    this.getItem = function () {
        var deferred = $q.defer();
        deferred.resolve({
            title: 'Some title'
        });
        return deferred.promise;
    };

    $scope.item = this.getItem();
}

Html:

<input type="text" ng-model="item.title">
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Raman Chodźka
  • 558
  • 1
  • 7
  • 16
  • Could you show me how you assigned a promise returned by $http which worked the way you wanted? – Dogbert Dec 29 '12 at 09:33
  • @Dogbert, Here is pseudocode to illustrate what I was talking about: `$scope.item = $http({method: 'post', url: '/find/my/item/'}) .then(function (response) { return response.item; });` Another example that uses $resource approach can be found in this [tutorial](http://docs.angularjs.org/tutorial/step_11). Starting from the line: `Notice how in PhoneListCtrl we replaced ... with $scope.phones = Phone.query();` – Raman Chodźka Dec 29 '12 at 09:48
  • Oops, just created [test example](http://plnkr.co/edit/VP1Td3WtdM0E7n5HJH3W?p=preview), and it appears not to work with any promise – Raman Chodźka Dec 29 '12 at 10:03
  • Hey guys, to get it to work, I had to use `.success(function(){}).then(function(r){if (r.data["my-result"])return r.data["my-result"];});` – Joel Apr 11 '13 at 22:15

3 Answers3

14

You need to use the then() function on the promise object:

this.getItem().then(function(result) {
   $scope.item = result;
});

In your case I don't think you need a promise. Angular's $watch system will take care of things. Just return an object in your function, not a primitive type:

this.getItem = function () {
    var item = {};

    // do some async stuff
    $http.get(...).success(function(result) {
       item.title = result;
    });
    return item;
};

$scope.item = this.getItem();
Community
  • 1
  • 1
asgoth
  • 35,552
  • 12
  • 89
  • 98
  • I know what you mean. I've updated my answer. You have to let angular take care of it (it will do it automatically with its $watch system). – asgoth Dec 29 '12 at 11:07
  • The second example you gave doesn't look simpler than the first one ;) Besides, it's not going to work as expected, because $http.get() will be resolved with json representing _item_ , not just _title_ So `this.getItem().then(function(result) { $scope.item = result; });` looks quite acceptable (I just changed this.item = result to $scope.item = result) – Raman Chodźka Dec 29 '12 at 11:30
  • Ah, indeed that this should have been scope. I'll change it so you can accept it. – asgoth Dec 29 '12 at 11:36
  • I'm not sure this addresses the fact that AngularJS claims promises can be used during binding as though they were the result... The docs still say that and I'd like to know why his code didn't work. Perhaps it only works if the deferred resolves after the template has finished digesting? It's not typical to resolve synchronously before returning the promise. – TheXenocide May 21 '13 at 19:40
1

I believe the reason your first fiddle does not work is because you are essentially binding scope property item to a promise. When you attempt to alter the value by typing into the text field, angular notices the activity, and then reassigns/resets the value of item to the result of the promise (which hasn't changed).

The solution provided by @asgoth sets/assigns the value of item once, when the promise is resolved. There is no binding going on here (i.e, item is not bound to the promise), so altering the value via the textbox does alter the value.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
-1

Its like @Mark said, here you can find a Working Example of your snippet.

Basically you were returning an object and not binding the model itself.

$timeout(function(){
   $scope.item = {
      title: 'Some title'
   }; // Apply the binding
   deferred.resolve(); // Resolve promise
},2000); // wait 2 secs           
Ivo
  • 113
  • 2
  • 7