2012-12-06 10 views
15

Sto provando a generare un evento su $ rootScope ogni volta che viene avviata una chiamata ajax.AngularJS: è necessario attivare l'evento ogni volta che viene avviata una chiamata Ajax

var App = angular.module('MyApp'); 

App.config(function ($httpProvider) { 
    //add a transformRequest to preprocess request 
    $httpProvider.defaults.transformRequest.push(function() { 
     //resolving $rootScope manually since it's not possible to resolve instances in config blocks 
     var $rootScope = angular.injector(['ng']).get('$rootScope'); 
     $rootScope.$broadcast('httpCallStarted'); 

     var $log = angular.injector(['ng']).get('$log'); 
     $log.log('httpCallStarted'); 
    }); 
}); 

L'evento "httpCallStarted" non viene attivato. Sospetto che non sia corretto utilizzare $ rootScope o qualsiasi altro servizio di istanza nei blocchi di configurazione. In tal caso, come posso ottenere un evento ogni volta che viene avviata una chiamata http, senza dover passare un oggetto config ogni volta che effettuo una chiamata?

Grazie in anticipo

+0

Sono abbastanza sicuro che le chiamate a angular.injector (['ng']) sono dove stai andando male. Questo non ti restituisce la funzione di injector che viene effettivamente utilizzata con la tua applicazione e quindi quando cerchi di ottenere $ rootScope ottieni effettivamente un rootScope $ diverso da quello che pensi di essere. L'unico modo in cui so come ottenere il vero iniettore è attraverso l'uso di angular.element (someselector) .injector() e su questo puoi chiamare .get ('$ rootScope'). Non so però se avrai ancora problemi con questo in un blocco di configurazione. –

risposta

16

Si può sempre avvolgere $ http in un servizio. Dal momento che i servizi vengono impostati solo una volta, è sufficiente che la fabbrica di servizi configuri gli eventi per te. Mi sembra un po 'schifo, onestamente, ma è un buon lavoro, dal momento che Angular non ha ancora un modo globale per farlo, a meno che non sia stato aggiunto qualcosa nella 1.0.3 di cui non sono a conoscenza.

Here's a plunker of it working

Ed ecco il codice:

app.factory('httpPreConfig', ['$http', '$rootScope', function($http, $rootScope) { 
    $http.defaults.transformRequest.push(function (data) { 
     $rootScope.$broadcast('httpCallStarted'); 
     return data; 
    }); 
    $http.defaults.transformResponse.push(function(data){ 
     $rootScope.$broadcast('httpCallStopped'); 
     return data; 
    }) 
    return $http; 
}]); 

app.controller('MainCtrl', function($scope, httpPreConfig) { 
    $scope.status = []; 

    $scope.$on('httpCallStarted', function(e) { 
    $scope.status.push('started'); 
    }); 
    $scope.$on('httpCallStopped', function(e) { 
    $scope.status.push('stopped'); 
    }); 

    $scope.sendGet = function(){ 
    httpPreConfig.get('test.json');  
    }; 
}); 
+0

Mi sembra bello, tuttavia, come risolvere il problema nel servizio risorse $, poiché dipende da $ http e non da httpPreConfig personalizzato? – bfcamara

+0

I * penso * dopo aver consultato per la prima volta questo servizio, aggiornerà i valori predefiniti per tutte le chiamate a $ http, anche quelle in $ risorsa. –

+0

Funziona. Grazie mille blogger – bfcamara

12

Ho verificato che questo codice funziona come previsto. Come accennato in precedenza, non stai recuperando l'iniettore che pensi di essere e devi recuperare quello in uso per la tua app.

discussionApp.config(function($httpProvider) { 
    $httpProvider.defaults.transformRequest.push(function(data) { 
    var $injector, $log, $rootScope; 
    $injector = angular.element('#someid').injector(); 

    $rootScope = $injector.get('$rootScope'); 
    $rootScope.$broadcast('httpCallStarted'); 

    $log = $injector.get('$log'); 
    $log.log('httpCallStarted'); 
    return data; 
    }); 
}); 
+2

Questa è la risposta corretta. –

+1

Per essere completamente corretti è necessario ricevere un argomento dati e restituire anche alcuni dati. – bfcamara

3

Il modo migliore per farlo è utilizzare un intercettore http. Verifica this link

11

Cagatay ha ragione. Migliore utilizzo $http intercettori:

app.config(function ($httpProvider, $provide) { 
    $provide.factory('httpInterceptor', function ($q, $rootScope) { 
     return { 
      'request': function (config) { 
       // intercept and change config: e.g. change the URL 
       // config.url += '?nocache=' + (new Date()).getTime(); 
       // broadcasting 'httpRequest' event 
       $rootScope.$broadcast('httpRequest', config); 
       return config || $q.when(config); 
      }, 
      'response': function (response) { 
       // we can intercept and change response here... 
       // broadcasting 'httpResponse' event 
       $rootScope.$broadcast('httpResponse', response); 
       return response || $q.when(response); 
      }, 
      'requestError': function (rejection) { 
       // broadcasting 'httpRequestError' event 
       $rootScope.$broadcast('httpRequestError', rejection); 
       return $q.reject(rejection); 
      }, 
      'responseError': function (rejection) { 
       // broadcasting 'httpResponseError' event 
       $rootScope.$broadcast('httpResponseError', rejection); 
       return $q.reject(rejection); 
      } 
     }; 
    }); 
    $httpProvider.interceptors.push('httpInterceptor'); 
}); 

penso interceptors opere per le versioni 1.1.x. dopo C'era responseInterceptors prima di quella versione.

+0

Non ho aggiunto un esempio nella mia risposta, ma sì, questo è esattamente ciò che uso nei miei progetti. –

+1

Questa è un'ottima risposta. Ho dovuto usare un servizio (per mostrare/nascondere lo spinner) all'interno dell'intercettatore, ma avevo usato .config per mostrarlo, e non è possibile usare il servizio in .config, ora con questa soluzione tutto funziona perfettamente e bene! –

+0

questa dovrebbe essere la risposta giusta – MilesStanfield

Problemi correlati