2014-04-07 21 views
12

Sto effettuando un servizio di registrazione, per estendere il servizio $ log angolare, salvando gli errori (o il debug se abilitato) in un database indexedDB. Ecco il codice:Dipendenza circolare di AngularJS

angular.module('appLogger', ['appDatabase']) 

.service('LogServices', function($log, Database) { 

    // ... 

    this.log = function(type, message, details) { 
     var log = {}; 
     log.type = type 
     log.context = this.context; 
     log.message = message; 
     log.dateTime = moment().format('YYYY-MM-DD HH:mm:ss'); 
     log.details = details || ''; 
     $log[type.toLowerCase()](log); 

     if (type === 'ERROR' || this.logDebug) { 
      Database.logSave(log); 
     } 
    }; 

    // ... 
}) 

Questo sta funzionando nei miei servizi come previsto. Ora il problema è che non posso usare il mio logger all'interno del servizio Database, perché genera un errore di dipendenza circolare. Capisco il problema ma non ho idea di come dovrei risolverlo ... Come dovrei aggirare questo?

Grazie per l'aiuto :-)

+1

Per favore dai un'occhiata alla mia risposta a una domanda simile: http://stackoverflow.com/questions/20647483/angularjs-injecting-service-into-a-http-interceptor-circular-dependency/ 21632161 # 21632161 –

risposta

28

Il motivo angolare si lamenta una dipendenza circolare è che ... beh ce n'è uno.
è un percorso molto pericoloso andare giù, ma se si sa cosa si sta facendo (le ultime parole famose), allora c'è una soluzione per aggirare che:

.service('LogServices', function($log, $injector) { 

    // ... 

    var Database; // Will initialize it later 

    this.log = function(type, message, details) { 
     /* Before using Database for the first time 
     * we need to inject it */ 
     if (!Database) { Database = $injector.get('Database'); } 

     var log = {}; 
     log.type = type 
     log.context = this.context; 
     log.message = message; 
     log.dateTime = moment().format('YYYY-MM-DD HH:mm:ss'); 
     log.details = details || ''; 
     $log[type.toLowerCase()](log); 

     if (type === 'ERROR' || this.logDebug) { 
      Database.logSave(log); 
     } 
    }; 

    // ... 
}) 

Sede, anche, questo short demo.

+0

Grazie, sta funzionando in questo modo. Ora, cosa pensi che sarebbe il percorso sicuro? Perché questo percorso è pericoloso? Puoi elaborare per favore? Mi piacerebbe molto fare le cose in modo angolare e, se possibile, non usare gli hack. La domanda è, ho un'altra opzione? – ImSoNuts

+3

La cosa pericolosa è entrare in un ciclo infinito che distruggerà la tua app (questo è ciò che Angular sta cercando di proteggerti in primo luogo). Se vuoi vederlo in azione, vai alla mia demo e decommenta la riga 'service1.serve();' Il modo "Angolare" non è creare dipendenze circolari (e in questo caso penso che tu non possa, perché tu abbiamo bisogno di 'Database' per fornire' LogServices' e volete anche avere 'LogServices' disponibile in' Database' (che è un paradosso in sé :)). – gkalpak

+1

Se si vuole "giocare sul sicuro", vedo 2 opzioni: 1.) Per 'Database' utilizzare un meccanismo di registrazione più semplice (che non si basa su' Database'). 2.) Non utilizzare lo stesso servizio 'Database' per' LogServices' e per il resto dell'app. Utilizza un servizio 'LogDatabase' più semplice (che non funziona su' LogServices') per passare a 'LogServices' e usa il tuo attuale servizio' Database' per il resto della tua app (che può tranquillamente usare 'LogServices' per la registrazione). (Spero che abbia senso: P) – gkalpak

3

Vedere this answer e in particolare Misko's blog e in particolare la domanda di Pietro nei commenti, in cui viene discusso quasi lo stesso problema.

risposta di Misko è (utilizzando il codice Java)

class Database() implements DB; 
class Logger(Database db); 
class LoggingDatabase(Logger log, Database db) implements DB; 

Quindi nella vostra applicazione, è necessario

.service('Database', ...) // DO NOT inject the $log or LogServices here 

.service('LogServices', function($log) {...}) // DO NOT inject Database here 

.service('LoggingDB', function(Database, LogServices) {...}) 

Usa LoggingDB per ogni parte della vostra applicazione in cui si desidera un database che registri. (O è un registratore che utilizza il database!)

Un altro pensiero

Come è possibile che si dispone di un database sul browser? Database è un wrapper per $ http o $ risorsa o qualcosa del genere? In questo caso, sono d'accordo con ExpertSystem nella sua opzione 2): non utilizzare $ http per errori di registrazione, perché se l'errore uccide $ http? Utilizzare invece XMLHTTPRequest. Vedi here per qualche discussione.

0

Ho affrontato questo problema quando si cerca di ignorare exceptionHandler

ecco il codice in cui il problema è apparso

angular 
    .factory('$exceptionHandler', ExceptionHandler); 

function exceptionHandler($log, sweetAlert) {// here is the problem with injecting sweetAlert 
    return function myExceptionHandler(exception, cause) { 
     //logErrorsToBackend(exception, cause); 
     sweetAlert.swal('Opps...', 'An error has occurred'); 
     $log.warn(exception, cause); 
    }; 
} 

e per risolvere il problema ho usato injector

angular 
    .factory('$exceptionHandler', ExceptionHandler); 

ExceptionHandler.$inject = ['$injector']; //better for minification 

function ExceptionHandler($injector) { 
    var $log, sweetAlert, $translate;// use variables for caching 

    return function exceptionHandler(exception, cause) { 
     // Add DI here to prevent circular dependency 
     $log = $log || $injector.get('$log'); 
     sweetAlert = sweetAlert || $injector.get('sweetAlert'); 
     $translate = $translate || $injector.get('$translate'); 
     //............ 
    } 

Questo è il link per ulteriori informazioni Injecting $http results in a Circular dependency

spero che questo ti aiuti

Problemi correlati