0

On my page I have a form of inputs that take in URLs

<div ng-repeat="parent in parents">
   <input ng-model="parent.url" type="text" /> 
</div>
<button ng-click="addParent()"> Add new link </button>

Later I have a button with ng-click that calls a function in my controller, which checks (asynchronously) if the pages with those URLs exist, along with some other (synchronous) checks.

Somehow I need to wait for results to process, collect them and then display some content depending on those results. I tried looping over all $http calls for each URL:

var results = [];
for (let i = 0; i < parents.length; i++) {
  let p = parents[i];
  $http.get(p.url).
  then((res) => { // pages exists
    results.push(true);
  }, (err) => { // page doesn't exist
    results.push(false);
  });
}

But this would return an empty list, since $http calls are asynchronous. Then I can't really check all of my results like this:

if(sync_values){ // this is fine
  if(async_values){ // this is never filled in
    // do something
  }
}

How can I check my results after all $http calls?


UPDATE:

I have tried to implement a factory with $q.all() that would collect promises and resolve them. The tricky bit was to resolve values and not promises; I needed to know which pages existed and which were missing. So I managed to come up with the following code for my factory:

let deferred = $q.defer();
let promises = []; 
angular.forEach(parents, function(parent) { 
  promises.push( $http.get(parent.url).then((res) => {
    return true;
  }, (err) => {
    return false;
  }) );
});

$q.all(promises).
then((res) => {
  deferred.resolve(res);
});
return deferred.promise;

Now I return a list of booleans (and I know which pages exist and which don't).

1 Answer 1

2

You should use $q:

angular.module('app', [])
.controller('ctrl', ['$q', '$scope', '$http', function($q, $scope, $http){

  $scope.handler = function(){              
     $scope.results = [];
     $scope.loaded = false;
     $scope.parents = [1,2,3,4,5,6,7,8,9,10];
     var promises = [];

     for (var parent in $scope.parents) {        
       let deffered = $q.defer();	  	 
       promises.push(deffered.promise);
       $http.get('https://stackoverflow.com').
         then(res => {  
           console.log('true');
           $scope.results.push(true);
           deffered.resolve(true);
         }, err => {          
           console.log('false');
           $scope.results.push(false);
           deffered.resolve(false);
         });
      }

      $q.all(promises).then(() => {
         console.log('completed');			
         $scope.loaded = true;
      });	  
    }
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app='app' ng-controller='ctrl'>
  <input type='button' value='Click' ng-click='handler()'/>
  <div ng-if='loaded'>
    <span ng-repeat='result in results track by $index'>{{result}} </span>
  </div>    
</div>

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

1 Comment

I used a slightly modified approach, where I shove the entire $http.get into promises. I also made a factory for that, to move the logic out of the controller.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.