«Неперехваченная ошибка: [$ injector: unpr]» с angular после развертывания


97

У меня есть довольно простое приложение Angular, которое отлично работает на моей машине разработчика, но после его развертывания выдает это сообщение об ошибке (в консоли браузера):

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

Если вы перейдете по ссылке, она сообщит вам, что ошибка возникает из-за того, что $ injector не может разрешить ваши зависимости. Это обычная проблема с angular, когда 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
            };
        }
    };
});

При уменьшении "$ scope", переданный в функцию контроллера, заменяется однобуквенным именем переменной. Это приведет к тому, что angular не будет знать о зависимости. Чтобы избежать этого, передайте имя зависимости вместе с функцией в виде массива.

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

И приложение angular появится в комплекте без изменений.


По поводу производительности, что лучше? Bundle () или ScriptBundle ()?
Thomas.Benz

@ Thomas.Benz Использование Bundle () отключит только минификацию ваших скриптов. Проблема здесь в том, что когда ScriptBundle () минимизирует некоторые сценарии Angular, он сокращает имена функций и выполняет другие связанные с ними вещи. И когда Angular пытается выполнить некоторые инъекции внутренних зависимостей или что-то в этом роде, он не может найти для этого подходящие функции, потому что их имена были изменены индивидуальным образом (например, с «SuperController» на «s» или иначе). Поэтому лучше оставить скрипты angular без изменений или попробовать использовать для минификации какую-нибудь другую библиотеку вместо стандартной.
Schnapz

1

Если у вас есть отдельные файлы для angular app \ resources \ директив и прочего, вы можете просто отключить минификацию вашего пакета angular app следующим образом (используйте new Bundle () вместо ScriptBundle () в файле конфигурации вашего пакета):


0

Добавьте службы $ http, $ scope в функцию контроллера, иногда, если они отсутствуют, возникают эти ошибки.


0

У меня была та же проблема, но проблема была в другой, я пытался создать службу и передать ей $ scope в качестве параметра.
Это еще один способ получить эту ошибку, как говорится в документации по этой ссылке:

Попытка внедрить объект области во что-либо, кроме контроллера или директивы, например в службу, также вызовет ошибку Неизвестного поставщика: $ scopeProvider <- $ scope. Это может произойти, если кто-то по ошибке зарегистрирует контроллер как службу, например:

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.