“ Uncaught Error: [$ injector: unpr]” ที่มีมุมหลังการปรับใช้


99

ฉันมีแอปพลิเคชัน Angular ที่ค่อนข้างเรียบง่ายซึ่งทำงานได้ดีบนเครื่อง dev ของฉัน แต่ล้มเหลวด้วยข้อความแสดงข้อผิดพลาดนี้ (ในคอนโซลเบราว์เซอร์) หลังจากที่ฉันปรับใช้:

Uncaught Error: [$injector:unpr] http://errors.angularjs.org/undefined/$injector/unpr?p0=tProvider%20%3C-%20t%20%3C-%20%24http%20%3C-%20%24compile

ไม่มีข้อความอื่นนอกเหนือจากนั้น เกิดขึ้นเมื่อโหลดหน้าเว็บครั้งแรก

ฉันใช้ ASP.NET MVC5, Angular 1.2RC3 และกดไปที่ Azure ผ่าน git

Googling ไม่ได้เปิดเผยสิ่งที่น่าสนใจ

ข้อเสนอแนะใด ๆ ?

แก้ไข:

ฉันใช้ TypeScript และกำหนดการอ้างอิงของฉันด้วย$injectตัวแปรเช่น:

export class DashboardCtrl {

    public static $inject = [
        '$scope',
        '$location',
        'dashboardStorage'
    ];

    constructor(
        private $scope: IDashboardScope,
        private $location: ng.ILocationService,
        private storage: IDashboardStorage) {
    }
}

ฉันเชื่อว่าควร (หรือมีวัตถุประสงค์เพื่อ) แก้ไขปัญหาการเปลี่ยนชื่อตัวแปรท้องถิ่นที่เกิดขึ้นระหว่างการลดขนาดและอาจทำให้เกิดข้อผิดพลาดนี้

ที่กล่าวว่ามีบางอย่างเกี่ยวข้องกับกระบวนการลดขนาดอย่างชัดเจนเช่นเมื่อฉันตั้งค่าBundleTable.EnableOptimizations = trueบนเครื่อง dev ฉันสามารถสร้างซ้ำได้

คำตอบ:


165

หากคุณไปที่ลิงค์ของคุณจะบอกคุณว่าข้อผิดพลาดเป็นผลมาจาก $ injector ไม่สามารถแก้ไขการอ้างอิงของคุณได้ นี่เป็นปัญหาทั่วไปเกี่ยวกับเชิงมุมเมื่อจาวาสคริปต์ถูกย่อ / อัปลักษณ์ / ไม่ว่าคุณจะทำอะไรเพื่อการผลิต

ปัญหาคือเมื่อคุณมีเช่นคอนโทรลเลอร์

angular.module("MyApp").controller("MyCtrl", function($scope, $q) {
  // your code
})

การลดขนาดจะเปลี่ยนไป$scopeและ$qเป็นตัวแปรสุ่มที่ไม่ได้บอกเชิงมุมว่าจะฉีดอะไร วิธีแก้ปัญหาคือการประกาศการอ้างอิงของคุณดังนี้:

angular.module("MyApp")
  .controller("MyCtrl", ["$scope", "$q", function($scope, $q) {
  // your code
}])

ที่ควรแก้ไขปัญหาของคุณ

เพียงแค่ทบทวนซ้ำทุกสิ่งที่ฉันได้กล่าวไว้จะอยู่ที่ลิงก์ที่ข้อความแสดงข้อผิดพลาดให้คุณ


2
ขอบคุณสำหรับคำแนะนำในการเยี่ยมชมลิงก์จริง - ฉันคิดว่ามันเป็นสิ่งประดิษฐ์ภายในไม่ใช่สิ่งที่เป็นประโยชน์ ปรากฎว่าฉันกำลังกำหนดการอ้างอิงทั้งหมดของฉันผ่าน$injectตัวแปรสาธารณะซึ่งฉันเชื่อว่าเทียบเท่ากับวิธีที่คุณแนะนำ (ดูdocs.angularjs.org/guide/di ) ฉันจะอัปเดตคำถามของฉัน
Ken Smith

2
ที่กล่าวว่ามีบางอย่างเกี่ยวข้องกับกระบวนการลดขนาดอย่างชัดเจนเช่นเมื่อฉันบังคับให้ย่อขนาด ASP.NET MVC บนเครื่อง dev ( BundleTable.EnableOptimizations = true;) ฉันสามารถสร้างปัญหาซ้ำได้ ดูต่อไป.
Ken Smith

ตกลงคิดออก ยังมีอีกที่หนึ่งที่ฉันกำลังทำ DI ที่ฉันลืมไปและมันกำลังยุ่งเหยิงในขั้นตอนการลดขนาด ขอบคุณนี่คือคำตอบที่ถูกต้อง
Ken Smith

นอกจากนี้ยังมีแพคเกจที่จะจัดการโดยอัตโนมัตินี้สำหรับคุณเรียกว่าngminและอัญมณีที่สอดคล้องกันสำหรับทางรถไฟที่เรียกว่าngmin รางรถไฟ
bradleygriffith

2
@RyanTuck - กล่าวอีกนัยหนึ่งคือด้วยรหัสที่ไม่ได้ปิดกั้น Angular สามารถดูชื่อตัวแปรในฟังก์ชันของคุณและคาดเดาสิ่งที่ต้องฉีดได้ดี แต่ด้วยรหัสย่อขนาดชื่อตัวแปรจะถูกมัดทั้งหมดดังนั้นจึงต้องการกลไกอื่น ๆ - กลไกที่ไม่เปลี่ยนแปลงเมื่อโค้ดถูกย่อขนาด - เพื่อให้ทราบว่าจะต้องฉีดอะไร นั่นคือจุดที่อาร์เรย์ $ ฉีดและกลไกอื่น ๆ เข้ามามีบทบาท
Ken Smith

13

พบปัญหาเดียวกันกับตัวเอง แต่คำจำกัดความตัวควบคุมของฉันดูแตกต่างจากข้างบนเล็กน้อย สำหรับคอนโทรลเลอร์ที่กำหนดไว้เช่นนี้:

function MyController($scope, $http) {
    // ...
}

เพียงเพิ่มบรรทัดหลังการประกาศเพื่อระบุว่าวัตถุใดที่จะฉีดเมื่อตัวควบคุมถูกสร้างอินสแตนซ์:

function MyController($scope, $http) {
    // ...
}
MyController.$inject = ['$scope', '$http'];

สิ่งนี้ทำให้การลดขนาดเล็กลง - ปลอดภัย


11

ปัญหานี้เกิดขึ้นเมื่อไม่ได้ระบุตัวควบคุมหรือคำสั่งเป็นอาร์เรย์ของการอ้างอิงและฟังก์ชัน ตัวอย่างเช่น

angular.module("appName").directive('directiveName', function () {
    return {
        restrict: 'AE',
        templateUrl: 'calender.html',
        controller: function ($scope) {
            $scope.selectThisOption = function () {
                // some code
            };
        }
    };
});

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

angular.module("appName").directive('directiveName', function () {
    return {
        restrict: 'AE',
        templateUrl: 'calender.html'
        controller: ['$scope', function ($scope) {
            $scope.selectThisOption = function () {
                // some code
            };
        }]
    };
});

10

หากคุณได้แยกไฟล์สำหรับ angular app \ resources \ directives และสิ่งอื่น ๆ คุณสามารถปิดการใช้งานการลดขนาดของชุดแอปเชิงมุมของคุณได้เช่นนี้ (ใช้ Bundle ใหม่ () แทน ScriptBundle () ในไฟล์กำหนดค่าบันเดิลของคุณ):

bundles.Add(
new Bundle("~/bundles/angular/SomeBundleName").Include(
               "~/Content/js/angular/Pages/Web/MainPage/angularApi.js",
               "~/Content/js/angular/Pages/Web/MainPage/angularApp.js",
               "~/Content/js/angular/Pages/Web/MainPage/angularCtrl.js"));

และแอปเชิงมุมจะปรากฏในกลุ่มที่ไม่มีการแก้ไข


เรื่องประสิทธิภาพอันไหนดีกว่ากัน? Bundle () หรือ ScriptBundle ()?
Thomas.Benz

@ Thomas.Benz การใช้ Bundle () จะปิดใช้งานการย่อขนาดสำหรับสคริปต์ของคุณเท่านั้น ปัญหาคือเมื่อ ScriptBundle () ย่อขนาดสคริปต์ Angular บางสคริปต์มันจะทำให้ชื่อฟังก์ชันสั้นลงและทำสิ่งอื่น ๆ ที่เกี่ยวข้อง และเมื่อ Angular พยายามทำการฉีดแบบพึ่งพาภายในหรืออะไรทำนองนั้นก็ไม่พบฟังก์ชันที่เหมาะสมสำหรับสิ่งนั้นเนื่องจากชื่อของพวกเขาถูกเปลี่ยนในลักษณะที่กำหนดเอง (เช่นจาก 'SuperController' เป็น 's' หรืออื่น ๆ ) ดังนั้นจึงเป็นการดีกว่าที่จะปล่อยให้สคริปต์เชิงมุมไม่ได้รับการแก้ไขหรือพยายามใช้ไลบรารีอื่นเพื่อลดขนาดแทนค่าเริ่มต้น
Schnapz

1

หากคุณได้แยกไฟล์สำหรับ angular app \ resources \ directives และสิ่งอื่น ๆ คุณสามารถปิดการใช้งานการลดขนาดของชุดแอปเชิงมุมของคุณได้เช่นนี้ (ใช้ Bundle ใหม่ () แทน ScriptBundle () ในไฟล์กำหนดค่าบันเดิลของคุณ):


0

เพิ่มบริการ $ http, $ ขอบเขตใน fucntion ตัวควบคุมบางครั้งหากไม่มีข้อผิดพลาดเหล่านี้จะเกิดขึ้น


0

ฉันมีปัญหาเดียวกัน แต่ปัญหาแตกต่างออกไปฉันพยายามสร้างบริการและส่ง $ scope ไปให้เป็นพารามิเตอร์
นั่นเป็นอีกวิธีหนึ่งในการรับข้อผิดพลาดนี้เนื่องจากเอกสารของลิงก์นั้นระบุว่า:

ความพยายามที่จะฉีดวัตถุขอบเขตลงในสิ่งที่ไม่ใช่ตัวควบคุมหรือคำสั่งเช่นบริการจะทำให้ผู้ให้บริการที่ไม่รู้จัก: $ scopeProvider <- $ scope error กรณีนี้อาจเกิดขึ้นหากมีการลงทะเบียนคอนโทรลเลอร์เป็นบริการโดยไม่ถูกต้องเช่น:

angular.module('myModule', [])
       .service('MyController', ['$scope', function($scope) {
        // This controller throws an unknown provider error because
        // a scope object cannot be injected into a service.
}]);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.