"Неприхована помилка: [$ injector: unpr]" з кутовим після розгортання


97

У мене досить простий кутовий додаток, який працює на моїй машині розробки досить добре, але не працює з цим повідомленням про помилку (на консолі браузера) після того, як я його розгортаю:

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.

Гуглінг не виявив нічого цікавого.

Будь-які пропозиції?

Редагувати:

Я використовую 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свій дев-апарат, я можу його відтворити.

Відповіді:


163

Якщо ви перейдете за вашим посиланням, це говорить про те, що помилка є результатом того, що інжектор $ не в змозі вирішити ваші залежності. Це поширена проблема з кутовим, коли javascript стає мінімізованим / непридатним / все, що ви робите з цим для виробництва.

Проблема полягає в тому, коли у вас є, наприклад, контролер;

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 ). Я оновлю своє запитання.
Кен Сміт

2
Однак, це явно має щось спільне з процесом мінімізації, тому що коли я змушую мінімізації ASP.NET MVC на своїй машині розробки ( BundleTable.EnableOptimizations = true;), я можу відтворити проблему. Продовжуючи дивитись.
Кен Сміт

Гаразд, зрозумів це. Було ще одне місце, коли я робив DI, про який я забув, і це заплуталося в процесі мінімізації. Дякую, це була правильна відповідь.
Кен Сміт

Також є пакет, який автоматично обробляє це для вас під назвою ngmin, і відповідний дорогоцінний камінь для Rails під назвою ngmin-rails .
bradleygriffith

2
@RyanTuck - Іншими словами, за допомогою немініфікованого коду Angular може просто переглядати назви змінних у ваших функціях та добре гадати, що потрібно вводити. Але із мінімізованим кодом усі назви змінних змінюються, тому йому потрібен якийсь інший механізм - механізм, який не змінюється, коли код буде мінімізований - щоб знати, що робити. Ось тут і грає $ inject масив та інші механізми.
Кен Сміт

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

Якщо ви розділили файли для кутових \ \ \ \ директив та інших речей, ви можете просто вимкнути мінімізацію свого кутового набору програм, як це (використовувати новий 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"));

І кутовий додаток з’явиться в комплекті немодифікованим.


Про продуктивність, що краще? Пакет () або ScriptBundle ()?
Thomas.Benz

@ Thomas.Benz Використання Bundle () відключить змінення лише для ваших сценаріїв. Проблема тут полягає в тому, що коли ScriptBundle () мінімізує деякі кутові сценарії, він скорочує назви функцій та виконує інші пов'язані речі. І коли Angular намагається зробити ін'єкції внутрішньої залежності чи щось подібне, він не міг знайти для цього належних функцій, тому що їхні назви були змінені на замовлення (наприклад, від "SuperController" на "s" чи інше). Тому краще залишити кутові сценарії без змін або спробувати використовувати якусь іншу бібліотеку для мінімізації замість типової.
Шнапз

1

Якщо ви розділили файли для кутових \ \ \ \ директив та інших речей, ви можете просто вимкнути мінімізацію свого кутового набору програм, як це (використовувати новий Bundle () замість ScriptBundle () у вашому файлі конфігурації пакета):


0

Додайте сервіси $ http, $ range в fucntion контролера, іноді якщо вони відсутні, ці помилки трапляються.


0

У мене була така ж проблема, але проблема була іншою, я намагався створити службу і передати $ range до неї як параметр.
Це ще один спосіб отримати цю помилку, як зазначено в документації цього посилання:

Спроба ввести об’єкт області у все, що не є контролером чи директивою, наприклад, службою, також призведе до невідомого постачальника: $ rangeProvider <- $ область помилки. Це може статися, якщо помилково зареєструвати контролер як послугу, напр .:

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.
}]);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.