javascript - style - title html




Procesando $ respuesta http en servicio (8)

Recientemente publiqué una descripción detallada del problema que estoy enfrentando here en SO. Como no pude enviar una solicitud real de $http , utilicé el tiempo de espera para simular un comportamiento asíncrono. El enlace de datos de mi modelo para ver funciona correctamente, con la ayuda de @Gloopy

Ahora, cuando uso $http lugar de $timeout (probado localmente), pude ver que la solicitud asíncrona fue exitosa y los data se llenaron con la respuesta json en mi servicio. Pero, mi punto de vista no se está actualizando.

actualizado Plunkr here


Al vincular la interfaz de usuario a su matriz, querrá asegurarse de actualizar esa misma matriz directamente estableciendo la longitud en 0 e insertando los datos en la matriz.

En lugar de esto (que establece una referencia de matriz diferente a los data que su UI no conocerá):

 myService.async = function() {
    $http.get('test.json')
    .success(function (d) {
      data = d;
    });
  };

prueba esto:

 myService.async = function() {
    $http.get('test.json')
    .success(function (d) {
      data.length = 0;
      for(var i = 0; i < d.length; i++){
        data.push(d[i]);
      }
    });
  };

Aquí hay un violín que muestra la diferencia entre configurar una nueva matriz y vaciarla y agregarla a una existente. ¡No pude hacer funcionar tu plnkr pero espero que esto funcione para ti!


Aquí hay un Plunk que hace lo que quieres: http://plnkr.co/edit/TTlbSv?p=preview

La idea es que trabaje directamente con promesas y sus funciones "a continuación" para manipular y acceder a las respuestas devueltas de forma asíncrona.

app.factory('myService', function($http) {
  var myService = {
    async: function() {
      // $http returns a promise, which has a then function, which also returns a promise
      var promise = $http.get('test.json').then(function (response) {
        // The then function here is an opportunity to modify the response
        console.log(response);
        // The return value gets picked up by the then in the controller.
        return response.data;
      });
      // Return the promise to the controller
      return promise;
    }
  };
  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  // Call the async method and then do stuff with what is returned inside our own then function
  myService.async().then(function(d) {
    $scope.data = d;
  });
});

Aquí hay una versión un poco más complicada que almacena en caché la solicitud, así que solo la haces por primera vez ( http://plnkr.co/edit/2yH1F4IMZlMS8QsV9rHv?p=preview ):

app.factory('myService', function($http) {
  var promise;
  var myService = {
    async: function() {
      if ( !promise ) {
        // $http returns a promise, which has a then function, which also returns a promise
        promise = $http.get('test.json').then(function (response) {
          // The then function here is an opportunity to modify the response
          console.log(response);
          // The return value gets picked up by the then in the controller.
          return response.data;
        });
      }
      // Return the promise to the controller
      return promise;
    }
  };
  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  $scope.clearData = function() {
    $scope.data = {};
  };
  $scope.getData = function() {
    // Call the async method and then do stuff with what is returned inside our own then function
    myService.async().then(function(d) {
      $scope.data = d;
    });
  };
});

En lo que respecta al almacenamiento en caché de la respuesta en el servicio, aquí hay otra versión que parece más sencilla de lo que he visto hasta ahora:

App.factory('dataStorage', function($http) {
     var dataStorage;//storage for cache

     return (function() {
         // if dataStorage exists returned cached version
        return dataStorage = dataStorage || $http({
      url: 'your.json',
      method: 'GET',
      cache: true
    }).then(function (response) {

              console.log('if storage don\'t exist : ' + response);

              return response;
            });

    })();

});

este servicio devolverá los datos en caché o $http.get ;

 dataStorage.then(function(data) {
     $scope.data = data;
 },function(e){
    console.log('err: ' + e);
 });

En relación con esto pasé por un problema similar, pero no con Get o Post realizado por Angular sino con una extensión hecha por un tercero (en mi caso, Chrome Extension).
El problema al que me enfrenté es que la extensión de Chrome no regresaría then() por lo que no pude hacerlo de la forma en la solución anterior, pero el resultado sigue siendo asíncrono.
Así que mi solución es crear un servicio y proceder a una devolución de llamada

app.service('cookieInfoService', function() {
    this.getInfo = function(callback) {
        var model = {};
        chrome.cookies.get({url:serverUrl, name:'userId'}, function (response) {
            model.response= response;
            callback(model);
        });
    };
});

Entonces en mi control

app.controller("MyCtrl", function ($scope, cookieInfoService) {
    cookieInfoService.getInfo(function (info) {
        console.log(info);
    });
});

Espero que esto pueda ayudar a otros a obtener el mismo problema.


Que sea sencillo. Es tan simple como

  1. promise devolución en su servicio (no es necesario utilizarla en el servicio)
  2. Utilízalo then en tu controlador.

Manifestación. http://plnkr.co/edit/cbdG5p?p=preview

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

app.factory('myService', function($http) {
  return {
    async: function() {
      return $http.get('test.json');  //1. this returns promise
    }
  };
});

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function(d) { //2. so you can use .then()
    $scope.data = d;
  });
});

Realmente no me gusta el hecho de que, debido a la forma "prometedora" de hacer las cosas, el consumidor del servicio que utiliza $ http tiene que "saber" cómo desempaquetar la respuesta.

Solo quiero llamar algo y obtener los datos, de forma similar a la antigua $scope.items = Data.getData(); camino, que ahora está en desuso .

Lo intenté por un tiempo y no encontré una solución perfecta, pero aquí está mi mejor oportunidad ( Plunker ). Puede ser útil para alguien.

app.factory('myService', function($http) {
  var _data;  // cache data rather than promise
  var myService = {};

  myService.getData = function(obj) { 
    if(!_data) {
      $http.get('test.json').then(function(result){
        _data = result.data;
        console.log(_data);  // prove that it executes once
        angular.extend(obj, _data);
      }); 
    } else {  
      angular.extend(obj, _data);
    }
  };

  return myService;
}); 

Entonces el controlador:

app.controller('MainCtrl', function( myService,$scope) {
  $scope.clearData = function() {
    $scope.data = Object.create(null);
  };
  $scope.getData = function() {
    $scope.clearData();  // also important: need to prepare input to getData as an object
    myService.getData($scope.data); // **important bit** pass in object you want to augment
  };
});

Los defectos que ya puedo detectar son

  • Debe pasar el objeto al que desea agregar los datos, que no es un patrón intuitivo o común en Angular
  • getData solo puede aceptar el parámetro obj en la forma de un objeto (aunque también puede aceptar una matriz), que no será un problema para muchas aplicaciones, pero es una limitación dolorosa
  • $scope.data preparar el objeto de entrada $scope.data con = {} para convertirlo en un objeto (esencialmente lo que $scope.clearData() hace arriba), o = [] para una matriz, o no funcionará (nosotros ' Ya estoy teniendo que asumir algo acerca de lo que vienen los datos). Traté de hacer este paso de preparación EN getData , pero no getData suerte.

Sin embargo, proporciona un patrón que elimina la placa de la caldera de "promesa de desempaquetado" del controlador y puede ser útil en los casos en los que desee utilizar ciertos datos obtenidos de $ http en más de un lugar y mantenerlo en SECO.


Tuve el mismo problema, pero cuando estaba navegando en Internet entendí que $ http devolvía de forma predeterminada una promesa, luego podía usarlo con "luego" después de devolver los "datos". mira el código:

 app.service('myService', function($http) {
       this.getData = function(){
         var myResponseData = $http.get('test.json').then(function (response) {
            console.log(response);.
            return response.data;
          });
         return myResponseData;

       }
});    
 app.controller('MainCtrl', function( myService, $scope) {
      // Call the getData and set the response "data" in your scope.  
      myService.getData.then(function(myReponseData) {
        $scope.data = myReponseData;
      });
 });

Una manera mucho mejor creo que sería algo como esto:

Servicio:

app.service('FruitsManager',function($q){

    function getAllFruits(){
        var deferred = $q.defer();

        ...

        // somewhere here use: deferred.resolve(awesomeFruits);

        ...

        return deferred.promise;
    }

    return{
        getAllFruits:getAllFruits
    }

});

Y en el controlador puedes simplemente usar:

$scope.fruits = FruitsManager.getAllFruits();

Angular colocará automáticamente los awesomeFruits resueltos en $scope.fruits .





angular-http