9

I have a AngularJS application with a controllers.js and factories.js.

What I like is to do something with the values in the controller (which I get from the factories). My problem is, that these values are empty at the time I access them.

How can I wait for the response? Or where can I add a callback?

    Flashcards.controller('CardDeckDetailController', function($scope, $routeParams, CardDeckService, CardService) {
    $scope.carddeck = CardDeckService.findCardDeckByID($routeParams.cardDeckID);
    $scope.cards = CardService.findCardsByCardDeckID($routeParams.cardDeckID);
    $scope.card = $scope.cards[0];
    $scope.cardLength = $scope.cards.length;

});

    Flashcards.factory('CardDeckService', function($resource) {
    var cardDeckService = $resource('/FlashcardsServer/rest/carddecks/:cardDeckID', {}, {});

    cardDeckService.findAllCardDecks = function() {
        return cardDeckService.query();
    };

    cardDeckService.findCardDeckByID = function(id) {
        return cardDeckService.get({ cardDeckID : id });
    };

    return cardDeckService;
});

What I like is to get the first car ($scope.cards[0]) and save it under $scope.card. But its always empty (same with cardsLength).

On the other hand if I print out the size from the partial view with (cards.length), I get the correct value.

Greets and Thanks Marc

ollo
  • 24,797
  • 14
  • 106
  • 155
mooonli
  • 2,355
  • 4
  • 23
  • 32
  • possible duplicate of [Angular JS: how to bind to promises](http://stackoverflow.com/questions/13033118/angular-js-how-to-bind-to-promises) – lucuma Apr 26 '13 at 15:02
  • @lucama: with the $resource service it's a different problem – Guillaume86 Apr 26 '13 at 16:48
  • You can still return promises with a resource though it is a little different. Here is an example: http://beta.plnkr.co/edit/ZXGdN3eRP2yabYILeDay?p=preview – lucuma Apr 26 '13 at 19:53

3 Answers3

6

You can get back the promise by accessing value.$then (has to go to the source code to find that):

Flashcards.controller('CardDeckDetailController', function($scope, $routeParams, CardDeckService, CardService) {
$scope.carddeck = CardDeckService.findCardDeckByID($routeParams.cardDeckID);
$scope.cards = CardService.findCardsByCardDeckID($routeParams.cardDeckID);
$scope.card =  $scope.cards.$then(function(){ return $scope.cards[0]; });
$scope.cardLength = $scope.cards.$then(function(){ return $scope.cards.length; });

edit: $then return the http response

Guillaume86
  • 14,341
  • 4
  • 53
  • 53
  • Hi Guilllaume. Thanks for the idea. But that doesnt work. I get the message "Cannot call method '$then' of undefined" – mooonli Apr 26 '13 at 16:29
  • Looks like you have a bug in your CardService then, it can't be undefined, $resource return an object and hydrate it when it has a response – Guillaume86 Apr 26 '13 at 16:34
  • Or you mispelled the property in the line you call $then – Guillaume86 Apr 26 '13 at 16:37
  • I have the following lines: Service: cardDeckService.findAllCardDecks = function() { return cardDeckService.query(); }; controller: $scope.carddecks = CardDeckService.findAllCardDecks(); $scope.carddecks.$then( function(carddecks){ alert('TET'); return cards[0]; } ); Without the $then part all the carddecks appear on the view without exception. Otherwise I get the message: "Object has no method '$then'"... – mooonli Apr 26 '13 at 16:46
  • Wich version of angularJS do you use? $then was commited recently (1.1.3) – Guillaume86 Apr 26 '13 at 16:51
  • Hi Guillaume. I used 1.0.5. With 1.1.4 it works better. But if i try to print out the object I dont get the card array I expected... the following gives me [object Object] but if i try to handle it like an array (return cards[0]) i get "undefined"... $scope.card = $scope.cards.$then(function(cards) { alert(cards); return cards[0]; }); – mooonli Apr 26 '13 at 17:41
  • Ok I misread the source, try my edited code, hopefuly it will get the job done ;) – Guillaume86 Apr 26 '13 at 17:49
  • Great. It works now. What is the name in the function header for? I mean does it makes a difference if i put $then(function(xyz).. or $then(function(cards)... ? What is the object behind this? Or what can i use it for? :-) – mooonli Apr 26 '13 at 17:52
  • the argument passed to the $then callback is the http response: The response object has these properties: data – {string|Object} – The response body transformed with the transform functions. status – {number} – HTTP status code of the response. headers – {function([headerName])} – Header getter function. config – {Object} – The configuration object that was used to generate the request. Doc: http://docs.angularjs.org/api/ng.$http – Guillaume86 Apr 26 '13 at 17:56
  • don't forget to accept the answer if it's solving your problem – Guillaume86 Apr 26 '13 at 18:17
  • Thank you so much, Guillaume. You helped me a lot. Have a nice evening. – mooonli Apr 26 '13 at 18:36
3

as lucuma suggests, this can probably be handled with a promise. http://api.jquery.com/promise/ for the jquery promise http://docs.angularjs.org/api/ng.$q the angular promise is based on the jquery promise

this answer has a similar solution for multiple queries to complete AngularJS - wait for multiple resource queries to complete

so instead of

cardDeckService.findCardDeckByID = function(id) {
    return cardDeckService.get({ cardDeckID : id });
};

use

cardDeckService.findCardDeckbyID = function(id){
   var d = $q.defer();
   var result = cardDeckService.get(id, function() {
        $scope.card = $scope.cards[0];
        d.resolve(result);
   });
   return d.promise;
}

in case you havent used promises, they are a better way to do "callbacks"

there is mention of $then in a github checkin, but i havent seen anything on the angular documentation site. maybe it is now included to handle promises

Community
  • 1
  • 1
Anton
  • 7,709
  • 5
  • 31
  • 33
  • Hi Anton. Thanks for your help. So how can I then access the result on the controller this way? I would like to implement the callback within the controller and pass it to the service as param. – mooonli Apr 26 '13 at 16:30
0

I had the same problem in the past few days and I solved it this way:

cardDeckService.findCardDeckByID = function(id) {
        var toReturn = new Object();
        var something = cardDeckService.get({ cardDeckID : id }, function(){
            toReturn = something;
        });
        return toReturn;
    };

You first return an empty object (but NOT something that is "undefined"). When the DB call finishes AngularJS automagically updates the object toReturn. Also your view (if it is linked with the controller) will be updated.

The problem, doing your way, is that the findCardDeckByID returns an undefined value. So, $scope.card is undefined and it won't be automagically updated. Also your view, therefore, won't be updated.

superpuccio
  • 11,674
  • 8
  • 65
  • 93