Synchronous Call in Angular js

0

I want to know if there really is how to make synchronous calls with angularjs.

The problem I have is the following:

I have two URL1 and URL2. URL1._ in this first url what I do is get some values of asignaturas and c/u of them has a code. This code will then be used in my URL2 which will return the parallel of the subject depending on the code.

Currently what I have done is use promises in angularjs.

First, I go through URL1 and get its data[i].codigo and in turn I send it to URL2 so that I can return its corresponding parallel .... But it only returns the first posicion[i] and the rest does not .

I would like you to guide me with this please. Thank you.

Code:

.service('ServParalelos',function($http, $q){
  return {
      getAll: getAll
  }

  function getAll (guid_coe) {
      var defered = $q.defer();
      var promise = defered.promise;

      $http.get('http://carbono.utpl.edu.ec:8080/wscodigosqr/webresources/entidades.qrhorario/horarios_componente?guid_coe='+guid_coe)
          .success(function(data) {
              defered.resolve(data);
          })
          .error(function(err) {
              defered.reject(err)
          });

      return promise;
  }
})

My controller

$scope.datosComp=data; //esta variable es el data q obtengo de la URL1
    var Tamanio = $scope.datosComp.length;  
    for ( i=0; i < Tamanio; i++) { //Tamanio es del primer url o servicio
      **$scope.guid_coe** =$scope.datosComp[i].guid_coe;
      ServParalelos.getAll($scope.guid_coe).then(function(data) {
        $scope.datosA = data; //en mi sengundo servicio le paso como parametro guid_coe
      })
    }

My HTML

<ion-view view-title="Subjects">
  <ion-content class="fondo">
    <div class="list card">
      <div class="item item-input-inset">
        <label class="item-input-wrapper">
           <h4>
             Welcome
          </h4>
        </label>
      </div>
    </div>
    <div class="list card">
      <ion-list>
        <ion-item type="item-text-wrap" ng-repeat="i in datosComp" href="#/Gtuto/componentes/{{i.nom_coe}}">
          <h3>{{i.nom_coe}}</h3>    
          <h3 ng-repeat="i in InfoComp">{{i.paralelo}}</h3>  
        </ion-item>
      </ion-list>
    </div> 
  </ion-content>
</ion-view>
    
asked by Dimoreno 22.02.2016 в 23:32
source

3 answers

2

Before answering your question I have to mention that in ajax it is very bad idea to make a synchronous call. What is known as synchronous call is a call to ajax that blocks the execution of javascript until the request does not return with a result which is not your case and is in fact declared obsolete. Read the specification of XMLHttpRequest in the open method the third parameter async ; when set to false it is how you can send a synchronous call.

In angular a synchronous call is not possible (all calls are asynchronous) since the service $http what returns is a promise that will be reopened or rejected in the future with a certain value (the data sent by the server or the error).

I have also noticed that you are using this notation:

function getAll (guid_coe) {
  var defered = $q.defer();
  var promise = defered.promise;

  $http.get('url')
      .success(function(data) {
          defered.resolve(data);
      })
      .error(function(err) {
          defered.reject(err)
      });

  return promise;
}

Which is known as the antipatrón of the promises . Instead you should use something like this:

function getAll (guid_coe) {
  return $http.get('url');
}

Not only is it simpler but you are using the correct pattern. In addition, the success and error methods are obsolete, instead you should use then with this form:

promesa.then(function() {
    // success
}, function() {
    // error
});

Having mentioned in which practices you should not incur, let's return to your example. This is how your service should look.

.service('ServParalelos',function($http, $q){
  return {
      getAll: getAll,
      getOne: getOne
  }

  function getAll () {
      return $http.get('url1');
  }

  function getOne(guid_coe) {
      return $http.get('url2' + guid_coe);
  }
})

Using the $q.all([/*arreglo u objeto con promesas*/]) method you can do something when all the promises are resolved, for example to show all the results at the same time, the result obtained in then is also a array with the same order in which you made the requests

In your case it is an arrangement of requests so I recommend that the results in your $scope should be stored precisely in an array. If you do something like this:

// Tus resultados se mostrarán todos de un golpe
ServParalelos.getAll().then(function(response) {
    var promesas = [];
    $scope.datosComp=response.data;
    var Tamanio = $scope.datosComp.length;  
    for (var i=0; i < Tamanio; i++) {
        promesas.push(ServParalelos.getOne($scope.datosComp[i].guid_coe));
    }

    return $q.all(promesas);
}).then(function(resultados) {
    // en resultados esta un arreglo con todos los datos de tus llamadas a url2
    // se lo asignas al scope luego de extraerlos
    for (var i=0; i < Tamanio; i++) {
       $scope.datosComp[i].datosA = resultados[i].data;
    }
}, function(err) {
    // Hacer algo con el error
});

You can also do something like this:

ServParalelos.getAll().then(function(response) {
    // Tus resultados se muestran a medida que van llegando
    $scope.resultados = [];
    $scope.datosComp=response.data;
    var Tamanio = $scope.datosComp.length;  

    function successCb(resp) {
        $scope.resultados.push(resp.data)
    }

    function errorCb(error) {
        // hacer algo con el error
    }

    for ( i=0; i < Tamanio; i++) {       
        ServParalelos.getOne($scope.datosComp[i].guid_coe).then(successCb, errorCb);      
    }
}, function(err) {
    // Hacer algo con el error
});

With the peculiarity that your data may not be displayed in the same order as it is impossible to predict the order of asynchronous calls, so you must write the code as follows:

ServParalelos.getAll().then(function(response) {
    // Tus resultados se muestran a medida que van llegando
    $scope.datosComp=response.data;
    var Tamanio = $scope.datosComp.length;  

    function asignaAsignatura(indice) {
        function successCb(resp) {
            $scope.datosComp[indice].datosA = resp.data;
        }

        function errorCb(error) {
            // hacer algo con el error
        }

        ServParalelos.getOne($scope.datosComp[indice].guid_coe).then(successCb, errorCb); 
    }


    for (var i=0; i < Tamanio; i++) {       
        asignaAsignatura(i);   
    }
}, function(err) {
   // Hacer algo con el error
});
    
answered by 23.02.2016 / 17:12
source
0

Based on what you say I feel that this is an answer: link

The controller:

    // function somewhere in father-controller.js
    var makePromiseWithSon = function() {
        // This service's function returns a promise, but we'll deal with that shortly
        SonService.getWeather()
            // then() called when son gets back
            .then(function(data) {
                // promise fulfilled
                if (data.forecast==='good') {
                    prepareFishingTrip();
                } else {
                    prepareSundayRoastDinner();
                }
            }, function(error) {
                // promise rejected, could log the error with: console.log('error', error);
                prepareSundayRoastDinner();
            });
    };

The service:

 app.factory('SonService', function ($http, $q) {
    return {
        getWeather: function() {
            // the $http API is based on the deferred/promise APIs exposed by the $q service
            // so it returns a promise for us by default
            return $http.get('http://fishing-weather-api.com/sunday/afternoon')
                .then(function(response) {
                    if (typeof response.data === 'object') {
                        return response.data;
                    } else {
                        // invalid response
                        return $q.reject(response.data);
                    }

                }, function(response) {
                    // something went wrong
                    return $q.reject(response.data);
                });
        }
    };
});
    
answered by 23.02.2016 в 00:03
0

I would recommend that the service be implemented in this way     .service ('ServParalelos', function ($ http, $ q) {       return {           getAll: getAll,           getByGuidCoe: getByGuidCoe       }

  function getAll () {
      var defered = $q.defer();

      var url = 'http://carbono.utpl.edu.ec:8080/wscodigosqr/webresources/entidades.qrhorario/horarios_componente';

      $http.get(url)
          .success(function(data) {
              defered.resolve(data);
          })
          .error(function(err) {
              defered.reject(err)
          });

      return defered.promise;
  };

 function getByGuidCoe (guid_coe) {
      var defered = $q.defer();

      var url = 'http://carbono.utpl.edu.ec:8080/wscodigosqr/webresources/entidades.qrhorario/horarios_componente?guid_coe=' + guid_coe;

      $http.get(url)
          .success(function(data) {
              defered.resolve(data);
          })
          .error(function(err) {
              defered.reject(err)
          });

      return defered.promise;
  };

})

You define two methods one getAll() and another getByGuid() then if you separate the functionality, passing or not the filter to the url.

When invoking it from the controller, you would use

$scope.datosComp = [];
$scope.datosA = [];

ServParalelos.getAll().then(function(data) {

    $scope.datosComp=data; 
    angular.forEach(data, function(value, key) {

          ServParalelos.getByGuidCoe(value.guid_coe).then(function(data) {
            $scope.datosA.push(data); 
          })

        });

});

When you invoke the second method you must add the values that you receive in an array since you will get more than one, that is why I define the scope and use the push()

    
answered by 23.02.2016 в 00:20