0

Dear all I am having trouble with the scope of my $scope or how should I put it.

I am retrieving the data from my Service successfully but I´m having trouble with accessing $scope.players and $scope.tournament and I think it has something to do with being inside the service call. If I console.out() inside the service call everything is just fine. How can I be able access the data which is inside of the service call.

Version 1: Here console log simply states undefined.

.controller('SelectCtrl', ['$scope','$stateParams', '$location', '$window','playerService','tournamentService', function ($scope, $stateParams, $location, $window, playerService, tournamentService) {

     init();
     function init() {

         playerService.getPlayers().then(function (data) {
             $scope.players = [];
             angular.forEach(data, function (player, index) {
                 $scope.players.push(player.info);
             });
         });

         tournamentService.getTournaments().then(function (data) {
             var result = data.filter(function (element) {
                 if (element.ID == $stateParams.id) {
                     return true;
                 } else {
                     return false;
                 }
             });
             $scope.tournament = result;
         });
     };

     console.log($scope.tournament);//undefined
     console.log($scope.players); //undefined
}

Version 2:, Here console log simply states the Object {then: function, catch: function, finally: function} Which is not what I wan´t I want the data to be able to display it in my view.

.controller('SelectCtrl', ['$scope','$stateParams', '$location', '$window','playerService','tournamentService', function ($scope, $stateParams, $location, $window, playerService, tournamentService) {

     init();
     function init() {

         $scope.players = playerService.getPlayers().then(function (data) {
             $scope.players = [];
             angular.forEach(data, function (player, index) {
                 $scope.players.push(player.info);
             });
         });

        $scope.tournament = tournamentService.getTournaments().then(function (data) {
             var result = data.filter(function (element) {
                 if (element.ID == $stateParams.id) {
                     return true;
                 } else {
                     return false;
                 }
             });
             $scope.tournament = result;
         });
     };

     console.log($scope.tournament);//Object {then: function, catch: function, finally: function}

     console.log($scope.players);//Object {then: function, catch: function, finally: function}

}

Your help is really appreciated!

The Services:

.factory('playerService', function ($http,$q) {
    return {
        getPlayers: function () {
            //return the promise directly.
            var deferred = $q.defer();
            $http.get(webServiceUrl + 'api/Player/GetAllPlayers')
                      .success(function (data) {
                          //resolve the promise as the data
                          deferred.resolve(data);
                      }).error(function () {
                          deferred.reject();
                      });
            return deferred.promise;
        }
    }

})

.factory('tournamentService', function ($http,$q) {
    return {
        getTournaments: function () {
            //return the promise directly.
            var deferred = $q.defer();
            $http.get(webServiceUrl + 'api/Tournament/GetAllTournaments')
                      .success(function (data) {
                          //resolve the promise as the data
                          deferred.resolve(data);
                      }).error(function () {
                          deferred.reject();
                      });
            return deferred.promise;
        }
    }

})

Part of the view:

  <h1 style="display: inline-block; margin-left:15px;">Enter <i>{{tournament.Name}}</i></h1>
        <div class="row">
            <div class="selectinforow">
                <div class="col-xs-2 selectinfo">
                    <span>{{tournament.EntryFee}}$</span></br>
                    <span>Entry Fee</span>
                </div>
                <div class="col-xs-2 selectinfo">
                    <span>{{tournament.Entries}}</span></br>
                    <span>Entries</span>
                </div>
                <div class="col-xs-2 selectinfo">
                    <span>{{tournament.Size}}</span></br>
                    <span>Max Size</span>
                </div>
                <div class="col-xs-2 selectinfo">
                    <span>{{tournament.StartTime}}</span></br>
                    <span>Start Date</span>
                </div>
                <div class="col-xs-2 selectinfo">
                    <span>{{tournament.Entryfee*tournament.Entries}}$</span></br>
                    <span>Winnings</span>
                </div>
            </div>
        </div>
5
  • the second one is nonsense, because you just assign the deferred object to the variable... 1.version - try to call $scope.$apply(); after variable assignment (after $scope.tournament = result;) Commented Feb 18, 2014 at 16:58
  • 1
    @doodeec you should never need $scope.$apply when dealing with angular code. Commented Feb 18, 2014 at 17:01
  • You may also want to look into using a Resolve function and doing all of this data-handling inside your playerService. It really clogs up the controller doing it this way. Ideally you should be able to just say $scope.tournament = playerService.tournament; etc. It will be a promise still, but angular templates understand promises. Commented Feb 18, 2014 at 17:02
  • @JonathanRowny yes, but the service method's promise can be resolved inside jquery handler, and then it is a problem and you need to call apply... but this is not a case, I overlooked that console log is called outside of the promise callback Commented Feb 18, 2014 at 17:03
  • $scope.$apply() does not work and it gives : Action Already In Progress error. Commented Feb 18, 2014 at 17:35

2 Answers 2

2

So if you read your code carefully you will notice you are using a promise on the following line:

tournamentService.getTournaments().then(function (data) {
   // [your data is set here - AFTER the service call runs]
}

// [your print is here - run BEFORE service call runs]

The key to the "then" statement is it isn't executed right away, but is instead run when data is returned from the service call. In other words, you have your print in the wrong spot - I would expect the values to be undefined there. If you move the console.log statements into the promise (then) - I would expect to see the valid values. You can also put a break point in the browser debugger to see the values in the "then" function if you want to validate that things are working. Hope this puts you on the right track!

EDIT

Once the promise completes, angular automatically updates the view. Lets say you have the following in your view (just an example):

<h1 ng-bind="tournament.Title">Default Text</h1>

When the view/page loads you will see "Default Text". After the promise completes, if a tournament has been loaded, angular will automatically update the "h1" to now have the Title for that tournament. This happens because angular automatically runs an "$apply()" after a promise completes.

Sign up to request clarification or add additional context in comments.

7 Comments

Hi @drew_w yes I know easily print out(console.log) the values correctly inside the promise then. But then I am not able to access the variables/object in the View. It is just as undefined as the console.log() outside of the promise. Hope I am clear enough in my comment.
@AKlabs Whenever you have a deferred promise, angular will automatically run a $scope.$apply() after the promise function finishes. That means your "view" should automatically update without you needing to really do anything. I'll update my answer with some code!
This is still not working I had the binding. I will include the services as well.
@AKlabs I don't specifically see anything wrong here. When you debug in the browser do you see the data you expect coming back from the services? If so - the issue must have to do with the view itself. Maybe include some of your html/view code that is supposed to display the data!
Hi drew_w again thanks for your help, I added some of the view html/code.
|
0

Your code is executed before the promise response.

If you need to code "procedurally", you should $watch the scope variable as below to detect any changes.

For example:

$scope.$watch('tournament', function() {
 console.log($scope.tournament);
}, true);

3 Comments

Dear @Paul, this produces the error. TypeError: Cannot read property 'exp' of undefined. It is like inside the then promise that the $scope there is invisible to the rest of the controller which is bizarre because my ng-grid can pickup the data without a problem :S
It should be $scope.watch('tournament' you pass watch a string which is the name of a property to watch.
Thanks @Jonathan Rowny Sorry for the mistake ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.