AngularJS seed: การใส่ JavaScript ลงในไฟล์แยกกัน (app.js, controllers.js, directives.js, filters.js, services.js)


93

ฉันใช้แม่แบบเมล็ดเชิงมุมเพื่อจัดโครงสร้างแอปพลิเคชันของฉัน เริ่มแรกฉันใส่โค้ด JavaScript ทั้งหมดลงในไฟล์เดียว, main.js. ไฟล์นี้มีการประกาศโมดูลตัวควบคุมคำสั่งตัวกรองและบริการของฉัน แอปพลิเคชันทำงานได้ดีเช่นนี้ แต่ฉันกังวลเกี่ยวกับความสามารถในการปรับขนาดและการบำรุงรักษาเนื่องจากแอปพลิเคชันของฉันมีความซับซ้อนมากขึ้น ฉันสังเกตเห็นว่าเทมเพลต angular-seed มีไฟล์แยกกันสำหรับแต่ละไฟล์ดังนั้นฉันจึงพยายามกระจายรหัสของฉันจากmain.jsไฟล์เดียวไปยังไฟล์อื่น ๆ ที่กล่าวถึงในชื่อสำหรับคำถามนี้และพบในapp/jsไดเร็กทอรีของangularแม่แบบเมล็ด

คำถามของฉันคือฉันจะจัดการการอ้างอิงเพื่อให้แอปพลิเคชันทำงานได้อย่างไร เอกสารที่มีอยู่ที่พบที่นี่ไม่ชัดเจนในเรื่องนี้เนื่องจากแต่ละตัวอย่างที่ให้มาแสดงไฟล์ต้นฉบับ JavaScript ไฟล์เดียว

ตัวอย่างของสิ่งที่ฉันมีคือ:

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
}

ฉันจะจัดการการอ้างอิงได้อย่างไร

ขอบคุณล่วงหน้า.


2
มีบทความเกี่ยวกับเรื่องนี้ ตัวอย่างเช่นbriantford.com/blog/huuuuuge-angular-apps.htmlและบางโปรเจ็กต์เช่นyeoman มีสองวิธีในการเข้าถึงสิ่งนี้: การแยกส่วนประกอบตามชั้น (เช่นเชิงมุม - เมล็ดพันธุ์) หรือตามคุณลักษณะเช่นเดียวกับบทความที่แนะนำ
Eduard Gamonal

เมื่อคุณประกาศโมดูลเช่นangular.module ('myApp.service1', [])ฉันคิดว่าคุณต้องเพิ่มการอ้างอิงให้กับ[]เช่นangular.module ('myApp.service1', ['myApp.service2', 'myApp .service2 ']) . ฉันค่อนข้างใหม่กับ AngularJS ดังนั้นฉันอาจคิดผิด หากได้ผลโปรดแจ้งให้เราทราบแล้วฉันจะโพสต์คำตอบ
Danny Varod

บรรทัดนั้นควรแทรกตรงไหน? ฉันใส่angular.module('myApp.services', ['myApp.services']);ลงใน app.js โดยไม่มีโชค
ChrisDevo

@ChrisDevo 1. เมื่อคุณตอบกลับความคิดเห็นให้เริ่มต้นความคิดเห็นด้วย "@" และชื่อผู้ใช้เสมอ (โดยไม่เว้นวรรค) ดังนั้นผู้ใช้จะได้รับการแจ้งเตือน 2. myApp.services ควรจะขึ้นอยู่กับโมดูลอื่น ๆ angular.module('myApp.services', ['myApp.server', 'myApp.somethingElse'])ที่ไม่เกี่ยวกับตัวเองเช่น
Danny Varod

@DannyVarod คุณแก้ไขความคิดเห็นก่อนหน้านี้หรือไม่ ฉันอ่านมันเหมือนangular.module('myApp.service1', ['myApp.service1', 'myApp.service2'])เดิม มิฉะนั้นฉันจะไม่รวม myApp.services ไว้เป็นที่พึ่งพาของตัวเอง
ChrisDevo

คำตอบ:


108

ปัญหาเกิดจากคุณ "ประกาศใหม่" โมดูลแอปพลิเคชันของคุณในไฟล์ที่แยกจากกันทั้งหมด

นี่คือลักษณะการประกาศโมดูลแอป (ไม่แน่ใจว่าการประกาศเป็นคำที่ถูกต้อง) มีลักษณะดังนี้:

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

นี่คือสิ่งที่มอบหมาย (ไม่แน่ใจว่าการมอบหมายเป็นคำที่ถูกต้องหรือไม่) ให้กับโมดูลแอปพลิเคชันของคุณมีลักษณะดังนี้:

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

สังเกตว่าไม่มีวงเล็บเหลี่ยม

ดังนั้นรุ่นอดีตหนึ่งที่มีวงเล็บที่ควรจะใช้เพียงครั้งเดียวมักจะอยู่ในของคุณหรือapp.js main.jsไฟล์อื่น ๆ ที่เกี่ยวข้องทั้งหมดไม่ว่าจะเป็นตัวควบคุมคำสั่งตัวกรอง ... - ควรใช้เวอร์ชันหลังซึ่งเป็นไฟล์ที่ไม่มีวงเล็บเหลี่ยม

ฉันหวังว่ามันจะสมเหตุสมผล ไชโย!


9
ฉันพบวิธีแก้ปัญหานี้แล้ว myAppมันดูเหมือนว่าเพียงหนึ่งโมดูลเป็นสิ่งจำเป็น ในไฟล์ app.js ของฉันฉันสร้าง var สำหรับมันvar myApp = angular.module('myApp', []);ในไฟล์อื่น ๆ ทั้งหมดที่ฉันอ้างถึง var นี้ (เช่นmyApp.filter('myFilter', function(MyService) { /* filter code */ });ตราบใดที่ฉันเพิ่มชื่อไฟล์ในแท็กสคริปต์ใน html ของฉันฉันไม่จำเป็นต้องประกาศอื่นใด การพึ่งพาเทมเพลตโครงการเชิงมุมค่อนข้างสับสนในเรื่องนี้
ChrisDevo

1
ตอนนี้ฉันสับสนจริงๆ ฉันได้ไปกลับและออก var ทั่วโลกmyAppเพื่อที่ว่าตอนนี้มันเป็นโมดูลที่ไม่ระบุชื่อใน:app.js angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'myApp.controllers']);ในทุกไฟล์อื่น ๆ angular.module('myApp.filter', []).filter('myFilter', function(MyService) { /* filter code */ });ฉันยังประกาศโมดูลที่ไม่ระบุชื่อเช่นนี้ ตอนนี้แอปของฉันก็ใช้งานได้เช่นกัน ฉันดูประวัติรหัสของฉันแล้วและฉันไม่เห็นว่าสิ่งนี้แตกต่างไปจากที่ฉันใช้ตอนไหน
ChrisDevo

4
ฉันสัญญาว่าจะได้ผล ฉันใช้มันทุกวันเพื่อพัฒนาแอพเชิงมุม อีกครั้งฉันมีการประกาศangular.module('myApp', []);(สังเกตวงเล็บเหลี่ยม) ในไฟล์ js หลักของฉัน จากนั้นไฟล์อื่น ๆ ทั้งหมดอ้างถึงโมดูลโดยใช้angular.module('myApp').controllerหรือ.directiveไวยากรณ์
Justin L.

5
ข้อผิดพลาดเกิดขึ้นเนื่องจาก Angular กำลังมองหาโมดูลที่เรียกว่า myApp.controller, myApp.filters … แต่สิ่งเหล่านี้ไม่ใช่โมดูล แต่เป็นส่วนประกอบที่ขยายโมดูลหนึ่งที่เรียกว่า myApp ทุกอย่างควรใช้งานได้หากคุณลบ myApp ของคุณทั้งหมดออกจากการอ้างอิงโมดูลของคุณ เพียงแค่ให้วงเล็บที่ว่างเปล่า (ยกเว้นกรณีที่คุณกำลังอื่น ๆ รวมทั้งโมดูลเชิงมุมจริงเช่นngCookies, ngResource) เมื่อประกาศโมดูลของคุณหลักของแอป:angular.module('myApp', []);
จัสตินลิตร

1
อ่าโอเค. โดยการวางเหล่านั้นเช่นการพึ่งพาสำหรับโมดูลของแอปก็จะผิดพลาดเพราะมันมีจะพบพวกเขา หากคุณนำออกจากวงเล็บเหลี่ยมคุณสามารถโหลดได้ตามต้องการและแอปของคุณจะไม่สนใจ ngResourceเป็นหนึ่งในผู้ที่คุณวางไว้ในวงเล็บประกาศโมดูลของคุณ หากคำตอบของฉันช่วยได้การโหวตและการอนุมัติจะได้รับการชื่นชมมาก
Justin L.

12

หากคุณต้องการใส่ส่วนต่างๆของแอปพลิเคชันของคุณ ( filters, services, controllers) ไว้ในไฟล์ทางกายภาพที่แตกต่างกันคุณต้องทำสองสิ่ง:

  1. ประกาศเนมสเปซเหล่านั้น (เนื่องจากไม่มีคำที่ดีกว่า) ในapp.jsไฟล์ของคุณหรือในแต่ละไฟล์
  2. อ้างถึงเนมสเปซเหล่านั้นในแต่ละไฟล์

ดังนั้นคุณapp.jsจะมีลักษณะดังนี้:

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

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

และในแต่ละไฟล์:

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

ทั้งหมดนี้สามารถรวมกันเป็นสายเดียว:

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

ส่วนที่สำคัญคือการที่คุณไม่ควร redefine angular.module('myApp'); ซึ่งจะทำให้ถูกเขียนทับเมื่อคุณสร้างอินสแตนซ์คอนโทรลเลอร์ของคุณอาจไม่ใช่สิ่งที่คุณต้องการ


1
ฉันชอบวิธีนี้คุณสามารถใช้เพื่อสร้างโครงสร้างชั้น (บอกว่าคอนโทรลเลอร์ของคุณต้องการบริการหรือตัวกรอง) โปรดทราบว่าฉันยังพบว่าเมื่อมีการฉีดการพึ่งพาย่อย (เช่นตัวกรองสำหรับคอนโทรลเลอร์) แล้วก็ยังมีให้ในผู้ปกครองทั้งหมดข้างต้น (หากมองเห็นเป็นต้นไม้) โดยไม่ต้องประกาศการฉีดซ้ำเพียงแค่อย่า ' อย่าลืมมันถ้าคุณเปลี่ยนเด็กและใช้มันในผู้ปกครอง นอกจากนี้ฉันขอแนะนำว่าอย่าใส่มากกว่าหนึ่งโมดูล (เนมสเปซ) ในไฟล์และอย่าพยายามใช้เนมสเปซเดียวกันในหลายไฟล์
Gary

จะเกิดอะไรขึ้นถ้าฉันมีไฟล์คอนโทรลเลอร์สองไฟล์หรือไฟล์บริการสองไฟล์ อินสแตนซ์จะเกิดขึ้นสำหรับแต่ละไฟล์หรือไม่
Avinash Raj

3

คุณจะได้รับข้อผิดพลาดเพราะคุณไม่ได้กำหนดmyApp.servicesเลย สิ่งที่ฉันทำจนถึงตอนนี้คือการใส่คำจำกัดความเริ่มต้นทั้งหมดไว้ในไฟล์เดียวแล้วใช้ในอีกไฟล์หนึ่ง เช่นเดียวกับตัวอย่างของคุณฉันจะใส่:

app.js

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

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

นั่นควรกำจัดข้อผิดพลาดแม้ว่าฉันคิดว่าคุณควรอ่านบทความEduard Gamonal ที่กล่าวถึงในหนึ่งในความคิดเห็น


ขอบคุณ Torsten แต่ฉันได้อ่านบทความนั้นและเพิ่มบรรทัดangular.module('myApp.services', []);ลงในไฟล์ app.js ของฉัน ไม่ได้ช่วยแก้ปัญหาของฉัน
ChrisDevo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.