javascript - div - tags html
Procesando $ respuesta http en servicio (12)
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;
});
};
});
Debido a que es asíncrono, $scope
obtiene los datos antes de que se complete la llamada ajax.
Podría usar $q
en su servicio para crear una promise
y devolvérsela al controlador, y el controlador obtiene el resultado dentro de then()
llamar contra promise
.
En su servicio,
app.factory(''myService'', function($http, $q) {
var deffered = $q.defer();
var data = [];
var myService = {};
myService.async = function() {
$http.get(''test.json'')
.success(function (d) {
data = d;
console.log(d);
deffered.resolve();
});
return deffered.promise;
};
myService.data = function() { return data; };
return myService;
});
Luego, en su controlador:
app.controller(''MainCtrl'', function( myService,$scope) {
myService.async().then(function() {
$scope.data = myService.data();
});
});
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.
He leído http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/ [AngularJS nos permite simplificar nuestra lógica de controlador al hacer una promesa directamente en el alcance, en lugar de entregar manualmente el resuelto valor en una devolución de llamada exitosa.]
tan simple y práctico :)
var app = angular.module(''myApp'', []);
app.factory(''Data'', function($http,$q) {
return {
getData : function(){
var deferred = $q.defer();
var promise = $http.get(''./largeLoad'').success(function (response) {
deferred.resolve(response);
});
// Return the promise to the controller
return deferred.promise;
}
}
});
app.controller(''FetchCtrl'',function($scope,Data){
$scope.items = Data.getData();
});
Espero que esto ayude
Que sea sencillo. Es tan simple como
-
promise
devolución en su servicio (no es necesario utilizarla en el servicio) - 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ámetroobj
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 ENgetData
, pero nogetData
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.
Tosh Shimayama tiene una solución, pero puede simplificar mucho si usa el hecho de que $ http devuelve promesas y que las promesas pueden devolver un valor:
app.factory(''myService'', function($http, $q) {
myService.async = function() {
return $http.get(''test.json'')
.then(function (response) {
var data = reponse.data;
console.log(data);
return data;
});
};
return myService;
});
app.controller(''MainCtrl'', function( myService,$scope) {
$scope.asyncData = myService.async();
$scope.$watch(''asyncData'', function(asyncData) {
if(angular.isDefined(asyncData)) {
// Do something with the returned data, angular handle promises fine, you don''t have to reassign the value to the scope if you just want to use it with angular directives
}
});
});
Una pequeña demostración en coffeescript: http://plunker.no.de/edit/ksnErx?live=preview
Su plunker actualizado con mi método: http://plnkr.co/edit/mwSZGK?p=preview
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
.
Por favor intente el siguiente código
Puede dividir el controlador (PageCtrl) y el servicio (dataService)
''use strict'';
(function () {
angular.module(''myApp'')
.controller(''pageContl'', [''$scope'', ''dataService'', PageContl])
.service(''dataService'', [''$q'', ''$http'', DataService]);
function DataService($q, $http){
this.$q = $q;
this.$http = $http;
//... blob blob
}
DataService.prototype = {
getSearchData: function () {
var deferred = this.$q.defer(); //initiating promise
this.$http({
method: ''POST'',//GET
url: ''test.json'',
headers: { ''Content-Type'': ''application/json'' }
}).then(function(result) {
deferred.resolve(result.data);
},function (error) {
deferred.reject(error);
});
return deferred.promise;
},
getABCDATA: function () {
}
};
function PageContl($scope, dataService) {
this.$scope = $scope;
this.dataService = dataService; //injecting service Dependency in ctrl
this.pageData = {}; //or [];
}
PageContl.prototype = {
searchData: function () {
var self = this; //we can''t access ''this'' of parent fn from callback or inner function, that''s why assigning in temp variable
this.dataService.getSearchData().then(function (data) {
self.searchData = data;
});
}
}
}());