„Uncaught Error: [$ injector: unpr]” z kątowym po wdrożeniu


97

Mam dość prostą aplikację Angular, która działa dobrze na moim komputerze deweloperskim, ale nie wyświetla tego komunikatu o błędzie (w konsoli przeglądarki) po jej wdrożeniu:

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

Żadna inna wiadomość poza tym. Dzieje się tak, gdy strona ładuje się po raz pierwszy.

Używam ASP.NET MVC5, Angular 1.2RC3 i wypycham na platformę Azure za pośrednictwem git.

Googlowanie nie przyniosło nic interesującego.

Jakieś sugestie?

EDYTOWAĆ:

Używam TypeScript i definiuję moje zależności ze $injectzmienną, np:

export class DashboardCtrl {

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

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

Uważam, że powinno (lub ma na celu) obejście problemów związanych ze zmianą nazw zmiennych lokalnych, które pojawiają się podczas minifikacji i które mogą powodować ten błąd.

To powiedziawszy, ma to oczywiście coś wspólnego z procesem minifikacji, ponieważ kiedy ustawiam BundleTable.EnableOptimizations = truena mojej maszynie deweloperskiej , mogę to odtworzyć.

Odpowiedzi:


163

Jeśli podążasz za swoim łączem, informuje cię, że błąd wynika z tego, że $ injector nie jest w stanie rozwiązać twoich zależności. Jest to częsty problem z angularem, gdy javascript zostaje zminimalizowane / uglifikowane / cokolwiek robisz z nim do produkcji.

Problem występuje, gdy masz np. Kontroler;

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

Zmiany minifikacji $scopei $qdo zmiennych losowych, które nie powiedzieć kątowa co wstrzykiwać. Rozwiązaniem jest zadeklarowanie zależności w następujący sposób:

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

To powinno rozwiązać twój problem.

Aby powtórzyć, wszystko, co powiedziałem, znajduje się pod linkiem, który zawiera komunikat o błędzie.


2
Dziękuję za sugestię, aby faktycznie odwiedzić link - założyłem, że to jakiś wewnętrzny artefakt, a nie coś na moją korzyść. Jak się okazuje, definiuję wszystkie moje zależności za pomocą $injectzmiennej publicznej, co moim zdaniem jest równoważne z sugerowanym przez Ciebie sposobem (patrz docs.angularjs.org/guide/di ). Zaktualizuję moje pytanie.
Ken Smith,

2
To powiedziawszy, ma to oczywiście coś wspólnego z procesem minifikacji, ponieważ kiedy wymuszam minifikacje ASP.NET MVC na mojej maszynie deweloperskiej ( BundleTable.EnableOptimizations = true;), mogę odtworzyć problem. Ciągle patrzę.
Ken Smith,

OK, rozgryzłem to. Było inne miejsce, w którym wykonywałem DI, o którym zapomniałem, i to było pomieszane w procesie minifikacji. Dzięki, to była dobra odpowiedź.
Ken Smith

Istnieje również pakiet, który automatycznie zajmie się tym za Ciebie o nazwie ngmin i odpowiedni klejnot dla Railsów o nazwie ngmin-rails .
bradleygriffith,

2
@RyanTuck - Innymi słowy, używając niezminifikowanego kodu, Angular może po prostu spojrzeć na nazwy zmiennych w twoich funkcjach i zgadnąć, co należy wstrzyknąć. Jednak w przypadku zminimalizowanego kodu wszystkie nazwy zmiennych są zablokowane, więc potrzebny jest inny mechanizm - mechanizm, który nie zmienia się po zminimalizowaniu kodu - aby wiedzieć, co wstrzyknąć. W tym miejscu do gry wchodzą tablica $ inject i inne mechanizmy.
Ken Smith

13

Sam napotkałem ten sam problem, ale definicje kontrolera wyglądały trochę inaczej niż powyżej. W przypadku kontrolerów zdefiniowanych w ten sposób:

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

Po prostu dodaj wiersz po deklaracji wskazujący, które obiekty mają zostać wstrzyknięte podczas tworzenia instancji kontrolera:

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

Dzięki temu jest bezpieczny dla minifikacji.


11

Ten problem występuje, gdy kontroler lub dyrektywa nie są określone jako tablica zależności i funkcji. Na przykład

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

Po zminimalizowaniu „$ scope” przekazany do funkcji kontrolera jest zastępowany jednoliterową nazwą zmiennej. To sprawi, że kątownik nie będzie miał pojęcia o zależności. Aby tego uniknąć, należy przekazać nazwę zależności wraz z funkcją jako tablicę.

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

10

Jeśli oddzieliłeś pliki dla dyrektyw angular app \ resources \ i innych rzeczy, możesz po prostu wyłączyć minifikację pakietu aplikacji kątowej w ten sposób (użyj new Bundle () zamiast ScriptBundle () w pliku konfiguracyjnym pakietu):

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"));

A aplikacja kątowa pojawiłaby się w pakiecie bez modyfikacji.


O wydajności, która jest lepsza? Bundle () czy ScriptBundle ()?
Thomas.Benz

@ Thomas.Benz Użycie Bundle () wyłączy tylko minifikację dla twoich skryptów. Problem polega na tym, że kiedy ScriptBundle () minimalizuje niektóre skrypty Angular, skraca nazwy funkcji i robi inne powiązane rzeczy. A kiedy Angular próbuje wykonać jakieś wewnętrzne wstrzyknięcia zależności lub coś w tym rodzaju, nie mógł znaleźć odpowiednich funkcji, ponieważ ich nazwy zostały zmienione w niestandardowy sposób (np. Z „SuperController” na „s” lub inaczej). Dlatego lepiej pozostawić niezmodyfikowane skrypty kątowe lub spróbować użyć innej biblioteki do minifikacji zamiast domyślnej.
Schnapz

1

Jeśli oddzieliłeś pliki dla dyrektyw angular app \ resources \ i innych rzeczy, możesz po prostu wyłączyć minifikację pakietu aplikacji kątowej w ten sposób (użyj new Bundle () zamiast ScriptBundle () w pliku konfiguracyjnym pakietu):


0

Dodaj usługi $ http, $ scope do funkcji kontrolera, czasami, jeśli ich brakuje, występują te błędy.


0

Miałem ten sam problem, ale problem był inny, próbowałem utworzyć usługę i przekazać do niej $ scope jako parametr.
To inny sposób na uzyskanie tego błędu, ponieważ dokumentacja tego linku mówi:

Próba wstrzyknięcia obiektu zakresu do czegokolwiek, co nie jest kontrolerem ani dyrektywą, na przykład usługą, spowoduje również zgłoszenie nieznanego dostawcy: $ scopeProvider <- $ scope error. Może się tak zdarzyć, jeśli przez pomyłkę zarejestruje się kontroler jako usługę, np .:

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.
}]);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.