เปิดใหม่และเพิ่มการอ้างอิงให้กับแอปพลิเคชันที่บูตแล้ว


89

มีวิธีฉีดการพึ่งพาในช่วงปลายให้กับโมดูลเชิงมุมที่บูตแล้วหรือไม่? นี่คือสิ่งที่ฉันหมายถึง:

สมมติว่าฉันมีแอปเชิงมุมทั่วทั้งไซต์ซึ่งกำหนดเป็น:

// in app.js
var App = angular.module("App", []);

และในทุกหน้า:

<html ng-app="App">

ต่อมาฉันกำลังเปิดแอปอีกครั้งเพื่อเพิ่มตรรกะตามความต้องการของหน้าปัจจุบัน:

// in reports.js
var App = angular.module("App")
App.controller("ReportsController", ['$scope', function($scope) {
  // .. reports controller code
}])

ตอนนี้พูดได้ว่าหนึ่งในบรรดาบิตตามความต้องการของตรรกะยังต้องพึ่งพาตัวเอง (เช่นngTouch, ngAnimate, ngResourceฯลฯ ) ฉันจะแนบเข้ากับแอพพื้นฐานได้อย่างไร ดูเหมือนจะไม่ได้ผล:

// in reports.js
var App = angular.module("App", ['ui.event', 'ngResource']); // <-- raise error when App was already bootstrapped

ฉันรู้ว่าฉันสามารถทำทุกอย่างล่วงหน้าได้นั่นคือ -

// in app.js
var App = angular.module("App", ['ui.event', 'ngResource', 'ngAnimate', ...]);

หรือกำหนดทุกโมดูลด้วยตัวเองจากนั้นฉีดทุกอย่างลงในแอปหลัก ( ดูข้อมูลเพิ่มเติมที่นี่ ):

// in reports.js
angular.module("Reports", ['ui.event', 'ngResource'])
.controller("ReportsController", ['$scope', function($scope) {
  // .. reports controller code
}])

// in home.js
angular.module("Home", ['ngAnimate'])
.controller("HomeController", ['$scope', '$http', function($scope, $http){
  // ...
}])

// in app.js, loaded last into the page (different for every page that varies in dependencies)
var App = angular.module("App", ['Reports', 'Home'])

แต่สิ่งนี้จะทำให้ฉันต้องเริ่มต้นแอพทุกครั้งด้วยการอ้างอิงของเพจปัจจุบัน

ฉันชอบที่จะรวมถึงพื้นฐานapp.jsในทุกหน้าและก็แนะนำส่วนขยายที่จำเป็นต้องใช้ในแต่ละหน้า ( reports.js, home.jsฯลฯ ) โดยไม่ต้องแก้ไขทุกตรรกะความร่วมมือฉันจะเพิ่มหรือสิ่งที่ลบ

มีวิธีแนะนำการอ้างอิงเมื่อแอปบูตแล้วหรือยัง? อะไรเป็นสำนวน (หรือวิธี) ในการทำสิ่งนี้? ฉันกำลังเอนเอียงไปทางวิธีแก้ปัญหาหลัง แต่ต้องการดูว่าวิธีที่ฉันอธิบายสามารถทำได้หรือไม่ ขอบคุณ.


คุณสามารถให้รหัสการทำงานขั้นสุดท้ายของคุณเพื่อดูได้หรือไม่?
Mangu Singh Rajpurohit

@ user2393267 อืมนานมากแล้วฉันไม่รู้ว่ายังมีรหัสนั้นอยู่ไหม ... ขอโทษด้วย ฉันคิดว่าในที่สุดฉันก็กลับมาดูการออกแบบเพราะโดยปกติแล้วเวลาที่ฉันต้องแฮ็คสิ่งต่างๆมันหมายความว่าฉันทำไม่ถูกต้อง ... อย่างไรก็ตามหากคุณยังคงมุ่งมั่นที่จะทำตามแนวทางนี้คำตอบด้านล่างก็ดูเหมือนจะเป็นแนวทางที่ดี .
sa125

คำตอบ:


115

ฉันแก้ไขได้ดังนี้:

อ้างอิงแอปอีกครั้ง:

var app = angular.module('app');

จากนั้นผลักดันข้อกำหนดใหม่ของคุณไปยังอาร์เรย์ข้อกำหนด:

app.requires.push('newDependency');

3
สิ่งนี้ใช้ได้กับฉัน +1 ฉันใช้สิ่งนี้สำหรับการพึ่งพาหลาย ๆ อย่างเช่น app.requires.push ('doctorCtrl', 'doctorService');
Amir

8
สิ่งนี้บันทึกสถาปัตยกรรมของฉัน
Saeed Neamati

3
มันไม่ได้ผลสำหรับฉัน ฉันกำลังเพิ่มการอ้างอิงแบบไดนามิกตามที่อธิบายไว้ แต่ Angular ยังไม่พบบริการจากโมดูลที่เพิ่ม
Slava Fomin II

6
และapp.requiresเป็นอาร์เรย์ดังนั้นหากคุณกำลังเพิ่มการอ้างอิงหลายรายการ (ดังในตัวอย่างรายงานของคุณ) คุณจะส่งต่อเป็นอาร์กิวเมนต์แยกกันไปยังpushเมธอด: app.requires.push('ui.event', 'ngResource');หรือถ้าการอ้างอิงเพิ่มเติมของคุณเป็นอาร์เรย์อยู่แล้ว:Array.prototype.push.apply(app.requires, ['ui.event', 'ngResource'])
Red Pea

2
บางครั้งฉันข้ามการโหวตเพราะฉันไม่ต้องการเข้าสู่ระบบไม่ใช่ครั้งนี้! ขอบคุณ!
CularBytes

12

ง่ายๆ ... รับตัวอย่างของโมดูลโดยใช้ getter ดังนี้: var app = angular.module ("App");

จากนั้นเพิ่มลงในคอลเล็กชัน "ต้องใช้" ดังนี้ app.requires [app.requires.length] = "ngResource";

อย่างไรก็ตามสิ่งนี้ได้ผลสำหรับฉัน โชคดี!


4
ที่ได้ผลสำหรับฉัน! ฉันมีคำถาม - ทำไมไม่ใช้: app.requires.push ("ngResource")?
Philipp Munin

9

ตามข้อเสนอนี้ในกลุ่ม Angular JS googleฟังก์ชันนี้ไม่มีอยู่ในขณะนี้ หวังว่าทีมหลักจะตัดสินใจเพิ่มฟังก์ชันนี้สามารถใช้งานได้เอง


4
ใช่สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับผู้ที่ไม่ต้องการสร้างสปา
regularmike

4

หากคุณต้องการเพิ่มการอ้างอิงหลายรายการพร้อมกันคุณสามารถส่งผ่านได้ดังนี้:

<script>
    var app = angular.module('appName');
    app.requires.push('dependencyCtrl1', 'dependencyService1');
</script>

4

ฉันตระหนักดีว่านี่เป็นคำถามเก่า แต่ยังไม่มีคำตอบที่ได้ผลดังนั้นฉันจึงตัดสินใจแบ่งปันวิธีแก้ไข

วิธีแก้ปัญหาต้องใช้ Forking Angular ดังนั้นคุณจึงไม่สามารถใช้ CDN ได้อีกต่อไป อย่างไรก็ตามการปรับเปลี่ยนมีน้อยมากดังนั้นฉันจึงแปลกใจว่าทำไมฟีเจอร์นี้ไม่มีอยู่ใน Angular

ฉันไปตามลิงก์ไปยังกลุ่มของ Googleที่ให้ไว้ในคำตอบอื่น ๆ สำหรับคำถามนี้ ฉันพบรหัสต่อไปนี้ซึ่งช่วยแก้ปัญหาได้:

instanceInjector.loadNewModules = function (mods) {
  forEach(loadModules(mods), function(fn) { instanceInjector.invoke(fn || noop); });
};

เมื่อฉันเพิ่มโค้ดนี้ไปยังสาย 4414 ในเชิงมุม 1.5.0 รหัสที่มา (ภายในcreateInjectorฟังก์ชั่นก่อนที่จะมีreturn instanceInjector;คำสั่ง) $injector.loadNewModules(['ngCookies']);มันช่วยให้ผมที่จะเพิ่มการพึ่งพาหลังจากร่วมมือเช่นนี้


เหรอ? ผิดปกติกับอะไรมากที่สุดโหวตคำตอบ ( ณ วันที่ 2017/06/26) ? ดูเหมือนว่าจะมีให้มากกว่าหนึ่งปีก่อนที่คุณจะโพสต์สิ่งนี้ คำตอบของคุณมีประโยชน์หรือไม่?
The Red Pea

@TheRedPea ดีไม่มีอะไรผิดปกติยกเว้นว่ามันไม่ได้แก้ปัญหาของฉัน แต่คำตอบนี้ทำได้
tjespe

และมันไม่ได้ผลสำหรับคุณเพราะฉันเดาว่าคุณได้บูตแอปของคุณแล้ว? ฉันก็สังเกตเช่นกัน ...
ถั่วแดง

2
หลังจากอ่านโพสต์ชุมชน Google ที่เชื่อมโยงฉันยิ่งแน่ใจว่า bootstrapping เป็นเหตุผลที่จำเป็นต้องแก้ปัญหาเช่นนี้ การโหวตเพิ่มขึ้นเนื่องจากคำถามเดิมถามเกี่ยวกับ "แอปพลิเคชันที่บูตแล้ว" ซึ่งไม่มีใครพูดถึง (แน่นอนว่า OP อาจสะกดผิด)
Red Pea

1

ตั้งแต่เวอร์ชั่น 1.6.7 ตอนนี้มันเป็นไปได้ที่จะโหลดโมดูลขี้เกียจหลังจากที่แอปได้รับการ bootstrapped $injector.loadNewModules([modules])ใช้ ด้านล่างนี้เป็นตัวอย่างที่นำมาจากเอกสาร AngularJS:

app.factory('loadModule', function($injector) {
   return function loadModule(moduleName, bundleUrl) {
     return getScript(bundleUrl).then(function() { $injector.loadNewModules([moduleName]); });
   };
})

โปรดอ่านเอกสารฉบับเต็มเกี่ยวกับ loadNewModulesเนื่องจากมี gotchas อยู่รอบ ๆ

นอกจากนี้ยังมีแอปตัวอย่างที่ดีมากโดย omkadiri ที่ใช้กับ ui-router

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.