Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

angularjs - How to use asynchronous calls in a loop in angular?

Each email in a list is to be sent to server and response to be be got from server that if it is a valid email.

So after all emails are checked the array should have :

[email protected] - valid
[email protected] - invalid
[email protected] - valid
[email protected] - invalid

The code to send the emails to server in a loop is like :

for(var i=0; i < isEmailValidList.length; i++) {
  var isEmailValid = User.validateEmail({email : isEmailValidList[i].email}, function(){
      isEmailValidList[i].isValid = isEmailValid.value;
  });
}

But the problem is that the calls are asynchronous, so for say i=0, the control will not go inside the function when i is 0. So when it does go inside the function value of i can be anything, mostly it is greater than length of array, so isEmailValidList[i] is undefined. If the call were synchronous then it would have waited for response and i would not have been incremented, but this is not the case.

So, how do I get the correct isValid response for its corresponding email ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Use promises. Angular can work with promises without any "special intervention", just like assigning a value to a scope variable, see the plnkr. Promises are the "base" to tame asynchronous programming to work like synchronous programming (while we don't have javascript generators in browsers) and is encouraged by Angular team because it's highly testable and maintainable

http://plnkr.co/edit/8BBS2a1kC24BHBWRYp9W?p=preview

// trying to emulate your service here

var app = angular.module('app', []);

app.factory('User', function($q, $timeout){
  User = {};

  User.validateEmail = function(email){
    var d = $q.defer();

    $timeout(function(){
      if (/(yahoo|gmail)/.test(email.email)){
        d.resolve(email); // return the original object, so you can access it's other properties, you could also modify the "email" object to have isValid = true, then resolve it
      } else {
        d.resolve(); // resolve it with an empty result
      }
    }, 1000, false);

    return d.promise;
  };

  return User;
  });

app.controller('MainCtrl', function(User, $q){
  this.emails = [
    {email: '[email protected]', name: 'Joe'},
    {email: '[email protected]', name: 'Abc'},
    {email: '[email protected]', name: 'XYZ'}, 
    {email: '[email protected]', name: 'test'}
  ];

  this.isEmailValidList = [];
  var promises = [];

  for(var i=0; i < this.emails.length; i++) {
    promises.push(
      User.validateEmail(this.emails[i]) 
    );
  }

  $q.all(promises).then(function(emails){ 
    this.isEmailValidList = emails.filter(function(e){ return e; });
  }.bind(this));

});

Notes: The $timeout is to emulate an asynchronous task, like a database call, etc. You could pass the entire emails array to the validation service then return the array, instead of creating an intermediate array of promises. With angular, you may assign a scope variable to a promise, and you can use it on ng-repeat without any changes to the code


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...