Semi di AngularJS: inserimento di JavaScript in file separati (app.js, controllers.js, directives.js, filters.js, services.js)


93

Sto usando il modello angular-seed per strutturare la mia applicazione. Inizialmente ho messo tutto il mio codice JavaScript in un unico file, main.js. Questo file conteneva la dichiarazione del modulo, i controller, le direttive, i filtri e i servizi. L'applicazione funziona bene in questo modo, ma sono preoccupato per la scalabilità e la manutenibilità poiché la mia applicazione diventa più complessa. Ho notato che il modello angular-seed ha file separati per ciascuno di questi, quindi ho tentato di distribuire il mio codice dal singolo main.jsfile in ciascuno degli altri file menzionati nel titolo di questa domanda e trovati nella app/jsdirectory dell'angular -modello di semi .

La mia domanda è: come gestisco le dipendenze per far funzionare l'applicazione? La documentazione esistente trovata qui non è molto chiara a questo proposito poiché ciascuno degli esempi forniti mostra un singolo file sorgente JavaScript.

Un esempio di quello che ho è:

app.js

angular.module('myApp', 
    ['myApp.filters',
     'myApp.services',
     'myApp.controllers']);

controllers.js

angular.module('myApp.controllers', []).
    controller('AppCtrl', [function ($scope, $http, $filter, MyService) {

        $scope.myService = MyService; // found in services.js

        // other functions...
    }
]);

filtri.js

angular.module('myApp.filters', []).
    filter('myFilter', [function (MyService) {
        return function(value) {
            if (MyService.data) { // test to ensure service is loaded
                for (var i = 0; i < MyService.data.length; i++) {
                    // code to return appropriate value from MyService
                }
            }
        }
    }]
);

services.js

angular.module('myApp.services', []).
    factory('MyService', function($http) {
        var MyService = {};
        $http.get('resources/data.json').success(function(response) {
            MyService.data = response;
        });
        return MyService;
    }
);

main.js

/* This is the single file I want to separate into the others */
var myApp = angular.module('myApp'), []);

myApp.factory('MyService', function($http) {
    // same code as in services.js
}

myApp.filter('myFilter', function(MyService) {
    // same code as in filters.js
}

function AppCtrl ($scope, $http, $filter, MyService) {
    // same code as in app.js
}

Come gestisco le dipendenze?

Grazie in anticipo.


2
ci sono alcuni articoli su questo. ad esempio, briantford.com/blog/huuuuuge-angular-apps.html e alcuni progetti, come yeoman. ci sono due modi per affrontare questo problema: separare i componenti per strati (come angular-seed) o per caratteristica, come suggeriscono alcuni articoli.
Eduard Gamonal

Quando dichiari un modulo, ad es. Angular.module ('myApp.service1', []), penso che tu debba aggiungere dipendenze a [] es. Angular.module ('myApp.service1', ['myApp.service2', 'myApp .service2 ']). . Sono abbastanza nuovo su AngularJS, quindi potrei sbagliarmi. Se funziona, fammelo sapere e posterò una risposta.
Danny Varod

Dove va inserita quella riga? Ho inserito angular.module('myApp.services', ['myApp.services']);app.js senza fortuna.
ChrisDevo

@ChrisDevo 1. Quando rispondi ai commenti, inizia sempre il commento con "@" e il nome dell'utente (senza spazi), in modo che l'utente riceva una notifica. 2. myApp.services dovrebbe dipendere da altri moduli, non da se stesso, ad es angular.module('myApp.services', ['myApp.server', 'myApp.somethingElse']).
Danny Varod

@DannyVarod, hai modificato il tuo commento precedente? L'ho letto come angular.module('myApp.service1', ['myApp.service1', 'myApp.service2'])originariamente. Altrimenti non avrei incluso myApp.services come propria dipendenza.
ChrisDevo

Risposte:


108

Il problema è causato dalla "ridichiarazione" del modulo dell'applicazione in tutti i file separati.

Questo è l'aspetto della dichiarazione del modulo dell'app (la dichiarazione non sicura è il termine giusto):

angular.module('myApp', []).controller( //...

Questo è l'aspetto dell'assegnazione (non sono sicuro se l'assegnazione sia il termine giusto) al modulo dell'applicazione:

angular.module('myApp').controller( //...

Notare la mancanza di parentesi quadre.

Quindi, la versione precedente, quella con le parentesi quadre, dovrebbe essere utilizzata solo una volta, di solito nel tuo app.jso main.js. Tutti gli altri file associati - controllori, direttive, filtri ... - dovrebbero utilizzare quest'ultima versione, quella senza le parentesi quadre.

Spero che abbia un senso. Saluti!


9
Ho trovato una soluzione a questo problema. Sembra che sia necessario un solo modulo myApp. Nel mio file app.js ho creato una var per esso var myApp = angular.module('myApp', []);In tutti gli altri file ho semplicemente fatto riferimento a questa var (ad esempio, myApp.filter('myFilter', function(MyService) { /* filter code */ });Finché ho aggiunto i nomi dei file nei tag script nel mio html, non ho avuto bisogno di dichiararne altri dipendenze. Il modello di progetto
angular

1
Adesso sono davvero confuso. Sono andato avanti e rimosso il var globale myApp, in modo che sia ormai un modulo anonimo app.js: angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'myApp.controllers']);. In tutti gli altri file ho anche dichiarato moduli anonimi come questo angular.module('myApp.filter', []).filter('myFilter', function(MyService) { /* filter code */ });. Anche la mia app ora funziona in questo modo. Ho esaminato la cronologia del codice e non riesco a vedere dove sia diverso da quello che avevo quando non funzionava.
ChrisDevo

4
Ti prometto che funziona. Lo uso ogni singolo giorno per sviluppare app angolari. Di nuovo, ho una dichiarazione di angular.module('myApp', []);(notare le parentesi quadre) nel mio file js principale. Quindi, tutti gli altri file fanno riferimento al modulo utilizzando la sintassi angular.module('myApp').controllero .directive.
Justin L.

5
Gli errori sono causati perché Angular sta cercando moduli chiamati myApp.controller, myApp.filters… ma, quelli non sono moduli, sono componenti che estendono l'unico modulo chiamato myApp. Tutto dovrebbe funzionare se rimuovi tutta la tua myApp. Qualunque cosa dalle dipendenze del tuo modulo. Basta tenere le parentesi quadre vuote (a meno che non si includono altri veri moduli angolari, ad esempio ngCookies, ngResource) quando si dichiara il modulo applicazione principale:angular.module('myApp', []);
Justin L.

1
Ah ok. Inserendoli come dipendenza per il modulo dell'app, si verificherà un errore perché deve trovarli. Se li togli dalle parentesi quadre, puoi caricarli a piacimento e alla tua app non importerà. ngResourceè sicuramente uno di quelli che metti tra parentesi di dichiarazione del modulo. Se la mia risposta fosse di aiuto, votarla e approvarla sarebbe molto apprezzata.
Justin L.

12

Se vuoi mettere le tue diverse parti della tua applicazione ( filters, services, controllers) in diversi file fisici, ci sono due cose che devi fare:

  1. Dichiara questi spazi dei nomi (per mancanza di un termine migliore) nel tuo app.jso in ogni file;
  2. Fare riferimento a tali spazi dei nomi in ciascuno dei file.

Quindi, il tuo app.jsassomiglierebbe a questo:

angular.module('myApp', ['external-dependency-1', 'myApp.services', 'myApp.controllers'])
.run(function() {
   //...

})
.config(function() {
  //...
});

E in ogni singolo file:

services.js

angular.module('myApp.services', []); //instantiates
angular.module('myApp.services') //gets
.factory('MyService', function() { 
  return {};
});

controllers.js

angular.module('myApp.controllers', []); //instantiates
angular.module('myApp.controllers')      //gets
.controller('MyCtrl', function($scope) {
  //snip...
})
.controller('AccountCtrl', function($scope) {
  //snip...
});

Tutto questo può essere combinato in una chiamata:

controllers.js
angular.module('myApp.controllers', []) 
.controller('MyCtrl', function($scope) {
 //snip...
});    

La parte importante è che non dovresti ridefinire angular.module('myApp'); questo causerebbe la sovrascrittura quando si istanziano i controller, probabilmente non quello che si desidera.


1
Mi piace questo approccio, puoi usarlo per creare una struttura a più livelli (supponiamo che il tuo controller abbia bisogno di un servizio o di un filtro). Nota, ho anche scoperto che una volta che una sotto-dipendenza (come quel filtro per un controller) viene iniettata, è anche disponibile in tutti i genitori sopra (se visualizzati come un albero) senza, ri-dichiarare l'iniezione, semplicemente don ' Non dimenticartene se cambi il bambino e lo utilizzi nel genitore. Inoltre, consiglierei di non inserire mai più di un modulo (spazio dei nomi) in un file e di non provare mai a utilizzare lo stesso spazio dei nomi in più file.
Gary

Cosa succede se ho due file di controller o due file di servizi? L'istanza avverrebbe per ogni singolo file?
Avinash Raj

3

Ricevi l'errore perché non hai myApp.servicesancora definito . Quello che ho fatto finora è mettere tutte le definizioni iniziali in un file e poi usarle in un altro. Come per il tuo esempio, metterei in:

app.js

angular.module('myApp.services', []);

angular.module('myApp', 
    ['myApp.services',
      ...]);

Questo dovrebbe eliminare l'errore, anche se penso che dovresti leggere l'articolo di Eduard Gamonal menzionato in uno dei commenti.


Grazie, Torsten, ma ho letto l'articolo e ho aggiunto la riga angular.module('myApp.services', []);al mio file app.js. Nessuno dei due risolve davvero il mio problema.
ChrisDevo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.