AngularJS-Startwert: JavaScript in separate Dateien einfügen (app.js, controller.js, directives.js, filter.js, services.js)

93

Ich verwende die Angular-Seed- Vorlage, um meine Anwendung zu strukturieren. Anfangs habe ich meinen gesamten JavaScript-Code in einer einzigen Datei zusammengefasst main.js. Diese Datei enthielt meine Moduldeklaration, Controller, Anweisungen, Filter und Dienste. Die Anwendung funktioniert gut, aber ich mache mir Sorgen um Skalierbarkeit und Wartbarkeit, da meine Anwendung komplexer wird. Ich habe festgestellt, dass die Angular-Seed-Vorlage für jede dieser Dateien separate Dateien enthält. Daher habe ich versucht, meinen Code aus der einzelnen main.jsDatei in jede der anderen Dateien zu verteilen, die im Titel dieser Frage erwähnt und im app/jsVerzeichnis der Angular- Datei gefunden wurden -Samenvorlage .

Meine Frage lautet: Wie verwalte ich die Abhängigkeiten, damit die Anwendung funktioniert? Die vorhandene Dokumentation hier ist in dieser Hinsicht nicht sehr klar, da jedes der angegebenen Beispiele eine einzelne JavaScript-Quelldatei zeigt.

Ein Beispiel für das, was ich habe, ist:

app.js.

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

controller.js

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

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

        // other functions...
    }
]);

filter.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
}

Wie verwalte ich die Abhängigkeiten?

Danke im Voraus.

ChrisDevo
quelle
2
Es gibt einige Artikel darüber. Zum Beispiel briantford.com/blog/huuuuuge-angular-apps.html und einige Projekte wie yeoman. Es gibt zwei Möglichkeiten, dies zu erreichen: Trennen von Komponenten durch Schichten (wie Winkelsamen) oder durch Merkmale, wie einige Artikel vorschlagen.
Eduard Gamonal
Wenn Sie ein Modul deklarieren, z. B. angle.module ('myApp.service1', []) , müssen Sie dem [] z. B. angle.module ('myApp.service1', ['myApp.service2', 'myApp .service2 ']). . Ich bin ziemlich neu bei AngularJS, also kann ich mich irren. Wenn dies klappt, lass es mich wissen und ich werde eine Antwort posten.
Danny Varod
Wo soll diese Zeile eingefügt werden? Ich habe angular.module('myApp.services', ['myApp.services']);ohne Glück in app.js gesetzt.
ChrisDevo
@ChrisDevo 1. Wenn Sie auf Kommentare antworten, beginnen Sie den Kommentar immer mit '@' und dem Namen des Benutzers (ohne Leerzeichen), damit der Benutzer eine Benachrichtigung erhält. 2. myApp.services sollten von anderen Modulen abhängig sein, nicht von sich selbst, z angular.module('myApp.services', ['myApp.server', 'myApp.somethingElse']).
Danny Varod
@DannyVarod, hast du deinen vorherigen Kommentar bearbeitet? Ich habe es wie angular.module('myApp.service1', ['myApp.service1', 'myApp.service2'])ursprünglich gelesen . Andernfalls hätte ich myApp.services nicht als eigene Abhängigkeit aufgenommen.
ChrisDevo

Antworten:

108

Das Problem wird dadurch verursacht, dass Sie Ihr Anwendungsmodul in all Ihren separaten Dateien "neu deklarieren".

So sieht die App-Modul-Deklaration aus (nicht sicher, ob die Deklaration der richtige Begriff ist):

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

So sieht die Zuordnung (nicht sicher, ob die Zuordnung auch der richtige Begriff ist) zu Ihrem Anwendungsmodul aus:

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

Beachten Sie das Fehlen eckiger Klammern.

Daher sollte die frühere Version, eine mit eckigen Klammern, nur einmal verwendet werden, normalerweise in Ihrem app.jsoder main.js. Alle anderen zugehörigen Dateien - Controller, Direktiven, Filter … - sollten die letztere Version verwenden, die ohne eckige Klammern.

Ich hoffe das ergibt Sinn. Prost!

Justin L.
quelle
9
Ich habe eine Lösung für dieses Problem gefunden. Es scheint, dass nur ein Modul benötigt wird myApp. In meiner Datei app.js habe ich eine Variable dafür erstellt. var myApp = angular.module('myApp', []);In allen anderen Dateien habe ich einfach auf diese Variable verwiesen (z. B. myApp.filter('myFilter', function(MyService) { /* filter code */ });Solange ich die Dateinamen in Skript-Tags in meinem HTML- Code hinzugefügt habe, musste ich keine andere deklarieren Abhängigkeiten. Die
Angular
1
Jetzt bin ich wirklich verwirrt. Ich bin zurückgegangen und habe die globale Variable entfernt myApp, sodass sie jetzt ein anonymes Modul in app.js: ist angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'myApp.controllers']);. In allen anderen Dateien habe ich auch solche anonymen Module deklariert angular.module('myApp.filter', []).filter('myFilter', function(MyService) { /* filter code */ });. Meine App funktioniert jetzt auch so. Ich habe meinen Codeverlauf durchgesehen und kann nicht sehen, wo dies anders ist als das, was ich getan habe, als es nicht funktioniert hat.
ChrisDevo
4
Ich verspreche dir, dass das funktioniert. Ich benutze es jeden Tag, um Angular Apps zu entwickeln. Wieder habe ich eine Deklaration von angular.module('myApp', []);(beachten Sie die eckigen Klammern) in meiner Haupt-js-Datei. Alle anderen Dateien verweisen dann mithilfe der Syntax angular.module('myApp').controlleroder auf das Modul .directive.
Justin L.
5
Die Fehler werden verursacht, weil Angular nach Modulen namens myApp.controller, myApp.filters ... sucht. Dies sind jedoch keine Module, sondern Komponenten, die das eine Modul namens myApp erweitern. Alles sollte funktionieren, wenn Sie alle Ihre myApp.whatever aus Ihren Modulabhängigkeiten entfernen. Halten Sie einfach die eckigen Klammern leer ist (es sei denn , Sie andere wahre Winkelmodule einschließlich, zB ngCookies, ngResource) , wenn Ihr Haupt App - Modul erklärt:angular.module('myApp', []);
Justin L.
1
Ah, okay. Von denen als Abhängigkeit für Ihre App - Modul platzieren, wird es Fehler , weil es hat sie zu finden. Wenn Sie sie aus den eckigen Klammern nehmen, können Sie sie nach Belieben laden, und Ihre App kümmert sich nicht darum. ngResourceist definitiv einer von denen, die Sie in Ihre Moduldeklarationsklammern setzen. Wenn meine Antwort helfen würde, wäre es sehr dankbar, wenn ich abstimmen und zustimmen würde.
Justin L.
12

Wenn Sie Ihre verschiedenen Teile Ihrer Anwendung ( filters, services, controllers) in verschiedenen physischen Dateien ablegen möchten, müssen Sie zwei Dinge tun:

  1. Deklarieren Sie diese Namespaces (mangels eines besseren Begriffs) in Ihrer app.jsoder in jeder Datei.
  2. Verweisen Sie auf diese Namespaces in jeder der Dateien.

Sie app.jswürden also so aussehen:

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

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

Und in jeder einzelnen Datei:

services.js

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

controller.js

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

All dies kann zu einem Anruf kombiniert werden:

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

Der wichtige Teil ist, dass Sie nicht neu definieren sollten angular.module('myApp'); Dies würde dazu führen, dass es überschrieben wird, wenn Sie Ihre Controller instanziieren, wahrscheinlich nicht das, was Sie wollen.

George Stocker
quelle
1
Ich mag diesen Ansatz, Sie können ihn verwenden, um eine abgestufte Struktur zu erstellen (sagen wir, Ihr Controller benötigt einen Dienst oder Filter). Beachten Sie, dass ich auch festgestellt habe, dass eine einmal abhängige Unterabhängigkeit (wie dieser Filter für einen Controller) auch für alle oben genannten Eltern verfügbar ist (wenn sie als Baum dargestellt wird), ohne die Injektion erneut zu deklarieren. Vergessen Sie es nicht, wenn Sie das Kind ändern und es im Elternteil verwenden. Außerdem würde ich empfehlen, niemals mehr als ein Modul (Namespace) in eine Datei einzufügen und niemals zu versuchen, denselben Namespace in mehreren Dateien zu verwenden.
Gary
Was ist, wenn ich zwei Controller-Dateien oder zwei Servicedateien habe? Wird die Instanziierung für jede einzelne Datei durchgeführt?
Avinash Raj
3

Sie erhalten den Fehler, weil Sie noch nicht definiert myApp.serviceshaben. Was ich bisher gemacht habe, ist, alle anfänglichen Definitionen in eine Datei zu setzen und sie dann in einer anderen zu verwenden. Wie für Ihr Beispiel würde ich Folgendes einfügen:

app.js.

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

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

Das sollte den Fehler beseitigen, obwohl ich denke, Sie sollten den Artikel lesen, den Eduard Gamonal in einem der Kommentare erwähnt hat.

Torsten Engelbrecht
quelle
Danke, Torsten, aber ich habe diesen Artikel gelesen und die Zeile angular.module('myApp.services', []);zu meiner app.js-Datei hinzugefügt . Beides spricht mein Problem nicht wirklich an.
ChrisDevo