0

With all the examples of services, factories, using $scope, using Controller as, I'm getting a bit confused. I have a simple ng-if expression that's returning undefined because the data to evaluate isn't ready yet:

<div ng-if="ctrl.AlreadyBoughtShoe('ShoeId')"> ... </div>

  ...

<script>
  (function() {

    var MyApp = angular.module("MyApp", []);

    MyApp.controller("MyAppController", function($http, $timeout, ShoeService) {
      var x = this

      loadRemoteData();

      function loadRemoteData() {
        ShoeService.GetShoes().then(function(Shoes){
          applyRemoteData(Shoes); 
        });
      }

      function applyRemoteData(Shoes) {
        x.Shoes = Shoes;
      }

      // FAILS HERE - Get undefined on the array
      x.AlreadyBoughtShoe = function(shoeId) {
        for (var i = 0; i < x.Shoes.length; i++) {
            // Do stuff 
        }               
      } 
    });

    MyApp.service("ShoesService", function($http, $q){

      return({
        GetShoes: GetShoes        
      });

      function GetShoes() {

        var request = $http({
            method: "GET",
            url: /MyUrl",
            cache: false,
            headers: $myHeaders            
        });

        return( request.then(handleSuccess, handleError));
      }

      function handleError( response ) {

        if (!angular.isObject(response.data) || !response.data.message) {
          return( $q.reject( "An unknown error occurred." ) );
        }

        return( $q.reject(response.data.message) );

      }

      function handleSuccess( response ) {
        return( response.data );            
      }

    });
  })();

</script>

Also, if it's relevant, in this particular case it has nothing to do with shoes... and the data is a person object, and there's no ng-repeat going on, so the ID for the "shoe" is manually typed in. I jumbled up my actual code to simplify this so I can understand the best way to deal with it, but that ng-if needs to evaluate after the data is ready to be evaluated.

I'm not sure how to best used promises or whatever else I need in this style of format, which I found an example of somewhere on the web a while back.

3
  • It's obviously a promise issue but I'm not sure the correct code. Commented Jul 14, 2015 at 21:52
  • possible duplicate of angularjs ng-show with promise expression Commented Jul 14, 2015 at 21:53
  • @djechlin me either. :) Commented Jul 14, 2015 at 21:53

4 Answers 4

1

This is happening because of the asynchronous nature of your service call in ShoeService. Your error is occurring due to code being called before x.Shoes = Shoes is resolved, essentially iterating over undefined. Try moving your logic into the then callback of your service. For example...

function loadRemoteData() {
   ShoeService.GetShoes().then(function(Shoes) {
       applyRemoteData(Shoes); 

       x.AlreadyBoughtShoe = function(shoeId) {
           for (var i = 0; i < x.Shoes.length; i++) {
               // Do stuff 
           }               
       } 
   });
}

You can probably move this to the end of applyRemoteData also if you wish. Either way you will need to execute this logic after you resolve x.Shoes

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

2 Comments

Thank you! I saw the possible duplicate. The ng-init is now discouraged, and with my particular setup it was hard to follow and translate into my situation. Not sure who voted to close, but wanted to say thanks. You saved me a headache regardless!
You are very welcome and I appreciate the feedback. Happy coding :)
0

You are right - when this code runs, x.Shoes is undefined. Change:

x.AlreadyBoughtShoe = function(shoeId) {
  for (var i = 0; i < x.Shoes.length; i++) {
      // Do stuff 
  }               
} 

to:

x.AlreadyBoughtShoe = function(shoeId) {
  for (var i = 0; i < (x.Shoes || []).length; i++) {
      // Do stuff
  }
}

Comments

0

You have multiple options.

  1. Evaluate the ng-if to false by default until you receive the data. You keep your AlreadyBoughtShoe method but you first check if you have data. If you don't have data yet just return false. You won't have an error anymore and when your promise is resolved your HTML should reflect that.

  2. You can delay controller initialization until your promise is resolved.

Comments

0

Maybe setting semaphore or something simillar can help. Promise evaluates after some period of time, and setting variable to true after succesfull call may help. Then add that variable to the ng-if condition, which would evaluate function only when variable is true, so the promise returned.

Set variable to and condition, which would evaluate when both are true.

<div ng-if="ctrl.loaded && ctrl.AlreadyBoughtShoe('ShoeId')"> ... </div>

Then set variable to true on success ( by default is set to false because of javascript ).

  function loadRemoteData() {
        ShoeService.GetShoes().then(function(Shoes){
          x.loaded = true;
          applyRemoteData(Shoes); 
        });
      }

This may help.

Comments

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.