img angularjs angular-resource

angularjs - img - ng-src angular 5



Como cancelar $ solicitudes de recursos (6)

(para Angular 1.2.28+) Hola a todos, solo quería hacer que sea fácil de entender, cómo manejé ese problema es el siguiente:

Aquí declaro parámetro de tiempo de espera

$scope.stopRequestGetAllQuestions=$q.defer();

entonces en lo uso de la siguiente manera

return $resource(urlToGet, {}, {get:{ timeout: stopRequestGetAllQuestions.promise }});

y si quiero detener las llamadas de $ recursos anteriores, solo resuelvo este objeto stopRequestGetAllQuestions que es todo.

stopRequestGetAllQuestions.resolve();

pero si quiero detener los anteriores y comenzar una nueva llamada a $ resource, hago esto después de stopRequestGetAllQuestions.resolve(); :

stopRequestGetAllQuestions = $q.defer();

Estoy tratando de averiguar cómo usar la propiedad de tiempo de espera de un recurso $ para cancelar dinámicamente las solicitudes pendientes. Idealmente, me gustaría poder simplemente cancelar solicitudes con ciertos atributos (según los parámetros enviados), pero parece que esto no es posible. Mientras tanto, solo estoy tratando de cancelar todas las solicitudes pendientes y luego restablecer la promesa de tiempo de espera para permitir nuevas solicitudes.

El problema parece ser que la configuración de $ resource solo permite una promesa única y estática para el valor del tiempo de espera. Tiene sentido cómo podría hacer esto si estuviera haciendo llamadas http $ individuales, ya que podría pasar nuevas promesas para el tiempo de espera, pero ¿cómo puede funcionar esto para un recurso $? He configurado un ejemplo de pulsador aquí: http://plnkr.co/edit/PP2tqDYXh1NAOU3yqCwP?p=preview

Aquí está mi código de controlador:

app.controller(''MainCtrl'', function($scope, $timeout, $q, $resource) { $scope.canceller = $q.defer(); $scope.pending = 0; $scope.actions = []; var API = $resource( ''index.html'', {}, { get: { method: ''GET'', timeout: $scope.canceller.promise } } ) $scope.fetchData = function() { if ($scope.pending) { $scope.abortPending(); } $scope.pending = 1; $scope.actions.push(''request''); API.get({}, function() { $scope.actions.push(''completed''); $scope.pending = 0; }, function() { $scope.actions.push(''aborted''); }); } $scope.abortPending = function() { $scope.canceller.resolve(); $scope.canceller = $q.defer(); } });

En este momento, el cancelador funciona cuando hay una solicitud pendiente, pero parece que no puedo restablecerla: una vez que se cancela una solicitud, todas las solicitudes futuras también serán canceladas.

Estoy seguro de que me estoy perdiendo algo, ya que poder cancelar solicitudes pendientes parece ser una característica muy importante de la mayoría de las aplicaciones web (al menos eso es lo que he creado).

Gracias


En nuestro intento de resolver esta tarea llegamos a la siguiente solución:

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Cancel resource</title> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular-resource.js"></script> <script> angular.module("app", ["ngResource"]). factory( "services", ["$resource", function($resource) { function resolveAction(resolve) { if (this.params) { this.timeout = this.params.timeout; this.params.timeout = null; } this.then = null; resolve(this); } return $resource( "http://md5.jsontest.com/", {}, { MD5: { method: "GET", params: { text: null }, then: resolveAction }, }); }]). controller( "Test", ["services", "$q", "$timeout", function(services, $q, $timeout) { this.value = "Sample text"; this.requestTimeout = 100; this.call = function() { var self = this; self.result = services.MD5( { text: self.value, timeout: $q(function(resolve) { $timeout(resolve, self.requestTimeout); }) }); } }]); </script> </head> <body ng-app="app" ng-controller="Test as test"> <label>Text: <input type="text" ng-model="test.value" /></label><br/> <label>Timeout: <input type="text" ng-model="test.requestTimeout" /></label><br/> <input type="button" value="call" ng-click="test.call()"/> <div ng-bind="test.result.md5"></div> </body> </html>

Cómo funciona

  1. $ resource combina la definición de acción, los parámetros de solicitud y los datos para construir un parámetro de configuración para una solicitud $ http.
  2. un parámetro de configuración que se pasa a una solicitud $ http se trata como un objeto de promesa, por lo que puede contener la función para inicializar la configuración.
  3. la función de la acción entonces puede pasar la promesa de tiempo de espera de los parámetros a la configuración.

Por favor mire " Cancelar solicitud de recursos de Angularjs " para más detalles.



Hola, hice un controlador personalizado basado en https://developer.rackspace.com/blog/cancelling-ajax-requests-in-angularjs-applications/

.factory(''ResourceFactory'', ["$q", "$resource", function($q, $resource) { function createResource(url, options, actions) { var actions = actions || {}, resource, outstanding = []; Object.keys(actions).forEach(function (action) { console.log(actions[action]); var canceller = $q.defer(); actions[action].timeout = canceller.promise; actions[action].Canceller = canceller; }); resource = $resource(url, options, actions); Object.keys(actions).forEach(function (action) { var method = resource[action]; resource[action] = function () { var deferred = $q.defer(), promise = method.apply(null, arguments).$promise; abortablePromiseWrap(promise, deferred, outstanding); return { promise: deferred.promise, abort: function () { deferred.reject(''Aborted''); }, cancel: function () { console.log(actions[action]); actions[action].Canceller.resolve("Call cancelled"); } }; }; }); /** * Abort all the outstanding requests on * this $resource. Calls promise.reject() on outstanding []. */ resource.abortAll = function () { for (var i = 0; i < outstanding.length; i++) { outstanding[i].reject(''Aborted all''); } outstanding = []; }; return resource; } return { createResource: function (url, options, actions) { return createResource(url, options, actions); } } }]) function abortablePromiseWrap(promise, deferred, outstanding) { promise.then(function () { deferred.resolve.apply(deferred, arguments); }); promise.catch(function () { deferred.reject.apply(deferred, arguments); }); /** * Remove from the outstanding array * on abort when deferred is rejected * and/or promise is resolved/rejected. */ deferred.promise.finally(function () { array.remove(outstanding, deferred); }); outstanding.push(deferred); } //Usage SERVICE factory("ServiceFactory", ["apiBasePath", "$resource", "ResourceFactory", function (apiBasePath, $resource, QiteResourceFactory) { return ResourceFactory.createResource(apiBasePath + "service/:id", { id: ''@id'' }, null); }]) //Usage Controller var result = ServiceFactory.get(); console.log(result); result.promise.then(function (data) { $scope.services = data; }).catch(function (a) { console.log("catch", a); }) //Actually cancels xhr request result.cancel();


La respuesta de Gecko IT funciona para mí, pero tuve que hacer algunas modificaciones para:

  • Permitir que la llamada ajax de recursos se cancele varias veces sin necesidad de volver a crear recursos
  • Hacer que los recursos sean compatibles con versiones anteriores: esto significa que no es necesario cambiar ningún código de aplicación (Controlador) excepto la fábrica de recursos
  • Hacer que el código sea compatible con JSLint

Esta es la implementación completa de fábrica de servicios (solo necesita poner el nombre del módulo correcto)

''use strict''; /** * ResourceFactory creates cancelable resources. * Work based on: https://.com/a/25448672/1677187 * which is based on: https://developer.rackspace.com/blog/cancelling-ajax-requests-in-angularjs-applications/ */ /* global array */ angular.module(''module_name'').factory(''ResourceFactory'', [''$q'', ''$resource'', function($q, $resource) { function abortablePromiseWrap(promise, deferred, outstanding) { promise.then(function() { deferred.resolve.apply(deferred, arguments); }); promise.catch(function() { deferred.reject.apply(deferred, arguments); }); /** * Remove from the outstanding array * on abort when deferred is rejected * and/or promise is resolved/rejected. */ deferred.promise.finally(function() { array.remove(outstanding, deferred); }); outstanding.push(deferred); } function createResource(url, options, actions) { var resource; var outstanding = []; actions = actions || {}; Object.keys(actions).forEach(function(action) { var canceller = $q.defer(); actions[action].timeout = canceller.promise; actions[action].Canceller = canceller; }); resource = $resource(url, options, actions); Object.keys(actions).forEach(function(action) { var method = resource[action]; resource[action] = function() { var deferred = $q.defer(), promise = method.apply(null, arguments).$promise; abortablePromiseWrap(promise, deferred, outstanding); return { $promise: deferred.promise, abort: function() { deferred.reject(''Aborted''); }, cancel: function() { actions[action].Canceller.resolve(''Call cancelled''); // Recreate canceler so that request can be executed again var canceller = $q.defer(); actions[action].timeout = canceller.promise; actions[action].Canceller = canceller; } }; }; }); /** * Abort all the outstanding requests on * this $resource. Calls promise.reject() on outstanding []. */ resource.abortAll = function() { for (var i = 0; i < outstanding.length; i++) { outstanding[i].reject(''Aborted all''); } outstanding = []; }; return resource; } return { createResource: function (url, options, actions) { return createResource(url, options, actions); } }; } ]);

El uso es el mismo que en el ejemplo de Gecko IT. Servicio de fábrica:

''use strict''; angular.module(''module_name'').factory(''YourResourceServiceName'', [''ResourceFactory'', function(ResourceFactory) { return ResourceFactory.createResource(''some/api/path/:id'', { id: ''@id'' }, { create: { method: ''POST'' }, update: { method: ''PUT'' } }); }]);

Uso en el controlador (compatible con versiones anteriores):

var result = YourResourceServiceName.create(data); result.$promise.then(function success(data, responseHeaders) { // Successfully obtained data }, function error(httpResponse) { if (httpResponse.status === 0 && httpResponse.data === null) { // Request has been canceled } else { // Server error } }); result.cancel(); // Cancels XHR request

Enfoque alternativo:

var result = YourResourceServiceName.create(data); result.$promise.then(function success(data, responseHeaders) { // Successfully obtained data }).catch(function (httpResponse) { if (httpResponse.status === 0 && httpResponse.data === null) { // Request has been canceled } else { // Server error } }); result.cancel(); // Cancels XHR request

Futuras mejoras:

  • No me gusta comprobar si la solicitud ha sido cancelada. Un mejor enfoque sería adjuntar el atributo httpResponse.isCanceled cuando se cancela la solicitud, y similar para abortar.

Una solución es volver a crear el recurso cada vez que lo necesite.

// for canceling an ajax request $scope.canceler = $q.defer(); // create a resource // (we have to re-craete it every time because this is the only // way to renew the promise) function getAPI(promise) { return $resource( ''index.html'', {}, { get: { method: ''GET'', timeout: promise } } ); } $scope.fetchData = function() { // abort previous requests if they are still running $scope.canceler.resolve(); // create a new canceler $scope.canceler = $q.defer(); // instead of using "API.get" we use "getAPI().get" getAPI( $scope.canceler.promise ).get({}, function() { $scope.actions.push(''completed''); $scope.pending = 0; }, function() { $scope.actions.push(''aborted''); }); }