Llamada Sincrona en Angular js

publicado por: Anonymous

Quiero saber si en realidad hay como realizar llamadas sincronas con angularjs.

El problema que tengo es el siguiente:

Tengo dos URL1 y URL2. URL1._ en esta primera url lo que hago es obtener unos ciertos valores de unas asignaturas y c/u de ellas tiene un codigo. Este codigo sera luego utilizado en mi URL2 el cual me devolvera el paralelo de la asignatura dependiendo del codigo.

Actualmente lo que he hecho es utilizar promesas en angularjs.

Para ello primero recorro el URL1 y obtengo su data[i].codigo y a su vez a este lo envio al URL2 para que me retorne su paralelo correspondiente….Pero solo me devuelve el de la primera posicion[i] y el resto no.

Quisiera que me puedan guiar con esto por favor Gracias.

Codigo:

.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;
  }
})

Mi 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
      })
    }

Mi 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>

solución

Antes de responder tu pregunta tengo que mencionar que en ajax es muy mala idea hacer una llamada síncrona. Lo que se conoce como llamada síncrona es una llamada a ajax que bloquea la ejecución del javascript hasta que la petición no regresa con un resultado lo cual no es tu caso y de hecho esta declarado como obsoleto. Lee la especificación de XMLHttpRequest en el método open el tercer parámetro async; al ponerse en false es como se puede enviar una llamada síncrona.

En angular una llamada síncrona no es posible(todas las llamadas son asíncronas) ya que el servicio $http lo que retorna es una promesa que se resoverá o rechazará en el futuro con un valor determinado (los datos enviados por el servidor o el error).

He notado ademas que estas usando esta notación:

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;
}

Lo cual se conoce como el antipatrón de las promesas. En su lugar debes usar algo como esto:

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

No sólo es mas simple sino que estás usando el patrón correcto. Además los métodos success y error son obsoletos, en su lugar debes usar then con esta forma:

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

Habiendo mencionado en que prácticas no debes incurrir volvamos a tu ejemplo. Así es como debería quedar tu servicio.

.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);
  }
})

Usando el método $q.all([/*arreglo u objeto con promesas*/]) puedes hacer algo cuando todas las promesas se resuelvan, por ejemplo para mostrar todos los resultados a la misma vez, el resultado obtenido en el then tambien es un arreglo con el mismo orden en el que hiciste las peticiones

En tu caso es un arreglo de peticiones por lo que te recomiendo que los resultados en tu $scope se deber guardar precisamente en un arreglo. Si haces algo como esto:

// 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
});

También puedes hacer algo como esto:

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
});

Con la particularidad de que tus datos pueden no mostrarse en el mismo orden ya que es imposible predecir el orden de las llamadas asíncronas por lo que debes escribir el código de la siguiente forma:

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
});
Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *