Benih AngularJS: menempatkan JavaScript ke dalam file terpisah (app.js, controllers.js, directives.js, filter.js, services.js)

93

Saya menggunakan template benih sudut untuk menyusun aplikasi saya. Awalnya saya memasukkan semua kode JavaScript saya ke dalam satu file main.js,. File ini berisi deklarasi modul, pengontrol, arahan, filter, dan layanan saya. Aplikasi berfungsi dengan baik seperti ini, tetapi saya khawatir tentang skalabilitas dan pemeliharaan karena aplikasi saya menjadi lebih kompleks. Saya perhatikan bahwa templat benih sudut memiliki file terpisah untuk masing-masing, jadi saya telah mencoba mendistribusikan kode saya dari satu main.jsfile ke masing-masing file lain yang disebutkan dalam judul pertanyaan ini dan ditemukan di app/jsdirektori sudut template benih .

Pertanyaan saya adalah: bagaimana cara mengelola dependensi agar aplikasi berfungsi? Dokumentasi yang ada yang ditemukan di sini tidak terlalu jelas dalam hal ini karena masing-masing contoh yang diberikan menunjukkan satu file sumber JavaScript.

Contoh dari apa yang saya miliki adalah:

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...
    }
]);

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
}

Bagaimana cara mengelola dependensi?

Terima kasih sebelumnya.

ChrisDevo
sumber
2
ada beberapa artikel tentang ini. misalnya, briantford.com/blog/huuuuuge-angular-apps.html , dan beberapa proyek, seperti yeoman. Ada dua cara untuk melakukan ini: memisahkan komponen berdasarkan lapisan (seperti biji bersudut) atau menurut fitur, seperti yang disarankan beberapa artikel.
Eduard Gamonal
Saat Anda mendeklarasikan modul misalnya angular.module ('myApp.service1', []) saya rasa Anda perlu menambahkan dependensi ke [] misalnya angular.module ('myApp.service1', ['myApp.service2', 'myApp .service2 ']). . Saya cukup baru di AngularJS, jadi saya mungkin salah. Jika ini berhasil, beri tahu saya dan saya akan memposting jawabannya.
Danny Varod
Di mana baris itu harus dimasukkan? Saya telah memasukkan angular.module('myApp.services', ['myApp.services']);ke app.js tanpa hasil.
ChrisDevo
@ChrisDevo 1. Saat Anda membalas komentar, selalu awali komentar dengan '@' dan nama pengguna (tanpa spasi), sehingga pengguna akan mendapat notifikasi. 2. myApp.services harus bergantung pada modul lain, bukan pada modul itu sendiri, misalnya angular.module('myApp.services', ['myApp.server', 'myApp.somethingElse']).
Danny Varod
@DannyVarod, apakah Anda mengedit komentar Anda sebelumnya? Saya membacanya seperti angular.module('myApp.service1', ['myApp.service1', 'myApp.service2'])aslinya. Jika tidak, saya tidak akan menyertakan myApp.services sebagai dependensinya sendiri.
ChrisDevo

Jawaban:

108

Masalahnya disebabkan karena Anda "mendeklarasikan" modul aplikasi Anda di semua file terpisah.

Seperti inilah tampilan deklarasi modul aplikasi (bukan deklarasi pasti adalah istilah yang tepat):

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

Ini adalah tugas (tidak yakin apakah tugas adalah istilah yang tepat) untuk modul aplikasi Anda terlihat seperti:

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

Perhatikan kurangnya tanda kurung siku.

Jadi, versi sebelumnya, yang memiliki tanda kurung siku, hanya boleh digunakan sekali, biasanya di app.jsatau main.js. Semua file terkait lainnya - pengontrol, arahan, filter ... - harus menggunakan versi terakhir, yang tanpa tanda kurung siku.

Saya harap itu masuk akal. Bersulang!

Justin L.
sumber
9
Saya telah menemukan solusi untuk masalah ini. Tampaknya hanya dibutuhkan satu modul myApp. Di file app.js saya, saya membuat var untuknya var myApp = angular.module('myApp', []);Di semua file lain, saya hanya merujuk ke var ini (misalnya, myApp.filter('myFilter', function(MyService) { /* filter code */ });Selama saya menambahkan nama file dalam tag skrip di html saya, saya tidak perlu mendeklarasikan yang lain dependensi. Template proyek angular-seed cukup membingungkan dalam hal ini.
ChrisDevo
1
Sekarang saya benar-benar bingung. Aku sudah kembali dan dihapus var global yang myApp, sehingga sekarang modul anonim di app.js: angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'myApp.controllers']);. Di semua file lain saya juga mendeklarasikan modul anonim seperti ini angular.module('myApp.filter', []).filter('myFilter', function(MyService) { /* filter code */ });. Aplikasi saya sekarang juga berfungsi seperti ini. Saya telah memeriksa riwayat kode saya dan saya tidak dapat melihat di mana perbedaan ini dengan apa yang saya lakukan ketika tidak berhasil.
ChrisDevo
4
Saya berjanji ini berhasil. Saya menggunakannya setiap hari untuk mengembangkan Aplikasi Angular. Sekali lagi, saya memiliki satu deklarasi angular.module('myApp', []);(perhatikan tanda kurung siku) di file js utama saya. Kemudian, semua file lainnya merujuk ke modul dengan menggunakan sintaks angular.module('myApp').controlleratau .directive.
Justin L.
5
Kesalahan terjadi karena Angular mencari modul yang disebut myApp.controller, myApp.filters… tetapi, itu bukan modul, mereka adalah komponen yang memperluas satu modul yang disebut myApp. Semuanya harus berfungsi jika Anda menghapus semua myApp.whatever dari dependensi modul Anda. Biarkan tanda kurung siku kosong (kecuali Anda menyertakan modul sudut nyata lainnya, misalnya ngCookies, ngResource) saat mendeklarasikan modul aplikasi utama Anda:angular.module('myApp', []);
Justin L.
1
Ah baiklah. Dengan menempatkan mereka sebagai dependensi untuk modul aplikasi Anda, itu akan kesalahan karena memiliki untuk menemukan mereka. Jika Anda mengeluarkannya dari tanda kurung siku, Anda dapat memuatnya sesuka hati dan aplikasi Anda tidak akan peduli. ngResourcepasti salah satu yang Anda tempatkan di tanda kurung deklarasi modul Anda. Jika jawaban saya benar-benar membantu, memberikan suara dan menyetujuinya akan sangat dihargai.
Justin L.
12

Jika Anda ingin meletakkan bagian yang berbeda dari aplikasi Anda ( filters, services, controllers) di file fisik yang berbeda, ada dua hal yang harus Anda lakukan:

  1. Deklarasikan namespace tersebut (karena tidak ada istilah yang lebih baik) di Anda app.jsatau di setiap file;
  2. Lihat namespace tersebut di setiap file.

Jadi, Anda app.jsakan terlihat seperti ini:

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

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

Dan di setiap file individual:

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...
});

Semua ini dapat digabungkan menjadi satu panggilan:

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

Bagian yang penting adalah Anda tidak harus mendefinisikan ulang angular.module('myApp'); yang akan menyebabkannya ditimpa saat Anda membuat instantiate pengontrol Anda, mungkin bukan yang Anda inginkan.

George Stocker
sumber
1
Saya suka pendekatan ini, Anda dapat menggunakannya untuk membuat struktur berjenjang (katakanlah pengontrol Anda membutuhkan layanan atau filter). Catatan, saya juga menemukan bahwa setelah sub-ketergantungan (seperti filter untuk pengontrol) disuntikkan, itu juga tersedia di semua orang tua di atas (jika divisualisasikan sebagai pohon) tanpa, mendeklarasikan ulang injeksi, cukup jangan ' t lupakan jika Anda mengubah anak dan menggunakannya sebagai orang tua. Juga saya akan merekomendasikan untuk tidak pernah meletakkan lebih dari satu modul (namespace) dalam sebuah file dan jangan pernah mencoba menggunakan namespace yang sama di banyak file.
Gary
Bagaimana jika saya memiliki dua file pengontrol atau dua file layanan? Apakah instantiate akan terjadi untuk setiap file?
Avinash Raj
3

Anda mendapatkan kesalahan karena Anda belum menentukan myApp.services. Apa yang saya lakukan sejauh ini adalah meletakkan semua definisi awal dalam satu file dan kemudian menggunakannya di file lain. Seperti contoh Anda, saya akan memasukkan:

app.js

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

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

Itu harus menghilangkan kesalahan, meskipun saya pikir Anda harus membaca artikel Eduard Gamonal yang disebutkan di salah satu komentar.

Torsten Engelbrecht
sumber
Terima kasih, Torsten, tetapi saya telah membaca artikel itu dan menambahkan baris angular.module('myApp.services', []);ke file app.js saya. Tidak ada yang benar-benar mengatasi masalah saya.
ChrisDevo