“Erro não detectado: [$ injector: despr]” com angular após a implantação

97

Eu tenho um aplicativo Angular bastante simples que funciona perfeitamente na minha máquina de desenvolvimento, mas está falhando com esta mensagem de erro (no console do navegador) depois de implantá-lo:

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

Nenhuma outra mensagem além dessa. Acontece quando a página é carregada pela primeira vez.

Estou executando a ASP.NET MVC5, Angular 1.2RC3 e enviando para o Azure via git.

Googling não encontrou nada de interessante.

Alguma sugestão?

EDITAR:

Estou usando o TypeScript e definindo minhas dependências com a $injectvariável, por exemplo:

export class DashboardCtrl {

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

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

Eu acredito que deveria (ou pretende) contornar os problemas de renomeação de variável local que surgem durante a minificação e que podem causar este erro.

Dito isso, claramente tem algo a ver com o processo de minificação, pois quando eu configuro BundleTable.EnableOptimizations = trueminha máquina de desenvolvimento, posso reproduzi-lo.

Ken Smith
fonte

Respostas:

163

Se você seguir o seu link, ele informará que o erro resulta do $ injector não ser capaz de resolver suas dependências. Este é um problema comum com o angular quando o javascript é reduzido / ampliado / o que quer que você esteja fazendo para produção.

O problema é quando você tem, por exemplo, um controlador;

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

As mudanças minification $scopee $qem variáveis aleatórias que não diz angular que injetar. A solução é declarar suas dependências assim:

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

Isso deve resolver o seu problema.

Apenas para reiterar, tudo o que eu disse está no link que a mensagem de erro fornece a você.

Stuart Nelson
fonte
2
Obrigado pela sugestão de visitar o link - presumi que fosse algum artefato interno, não algo para meu benefício. Acontece que estou definindo todas as minhas dependências por meio da $injectvariável pública, que acredito ser equivalente à maneira que você sugere (consulte docs.angularjs.org/guide/di ). Vou atualizar minha pergunta.
Ken Smith
2
Dito isso, claramente tem algo a ver com o processo de minificação, pois quando eu forço as minificações do ASP.NET MVC em minha máquina de desenvolvimento ( BundleTable.EnableOptimizations = true;), posso reproduzir o problema. Continuando a olhar.
Ken Smith
OK, descobri. Havia outro lugar que eu estava fazendo DI que eu tinha esquecido e estava ficando confuso no processo de minificação. Obrigado, esta foi a resposta certa.
Ken Smith
Também existe um pacote que tratará disso automaticamente para você, chamado ngmin, e uma gem correspondente para Rails, chamada ngmin-rails .
bradleygriffith,
2
@RyanTuck - Em outras palavras, com código não minimizado, o Angular pode apenas olhar para os nomes das variáveis ​​em suas funções e fazer uma boa estimativa sobre o que precisa ser injetado. Mas com o código reduzido, os nomes das variáveis ​​são todos eliminados, então ele precisa de algum outro mecanismo - um mecanismo que não muda quando o código é reduzido - para saber o que injetar. É aí que o array $ inject e os outros mecanismos entram em ação.
Ken Smith
13

Eu mesmo tive o mesmo problema, mas minhas definições de controlador pareciam um pouco diferentes das anteriores. Para controladores definidos assim:

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

Basta adicionar uma linha após a declaração indicando quais objetos injetar quando o controlador é instanciado:

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

Isso o torna seguro para a minimização.

Matt
fonte
11

Esse problema ocorre quando o controlador ou a diretiva não são especificados como uma matriz de dependências e funções. Por exemplo

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

Quando minimizado O '$ scope' passado para a função do controlador é substituído por um nome de variável de uma única letra. Isso tornará o angular sem noção da dependência. Para evitar isso, passe o nome da dependência junto com a função como um array.

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

Se você separou arquivos para angular app \ resources \ directives e outras coisas, você pode simplesmente desabilitar a minificação de seu pacote angular de app desta forma (use new Bundle () em vez de ScriptBundle () no arquivo de configuração do pacote):

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

E o aplicativo angular apareceria no pacote sem modificações.

Schnapz
fonte
Sobre desempenho, o que é melhor? Bundle () ou ScriptBundle ()?
Thomas.Benz
@ Thomas.Benz O uso de Bundle () desabilitará apenas a minificação de seus scripts. O problema aqui é que quando ScriptBundle () minimiza alguns scripts Angular, ele encurta os nomes das funções e faz outras coisas relacionadas. E quando o Angular tenta fazer algumas injeções de dependência interna, ou algo parecido, ele não consegue encontrar funções adequadas para isso, porque seus nomes foram alterados de forma personalizada (como de 'SuperController' para 's' ou então). Portanto, é melhor deixar os scripts angulares inalterados ou tentar usar alguma outra biblioteca para minificação em vez da padrão.
Schnapz
1

Se você separou arquivos para angular app \ resources \ directives e outras coisas, você pode simplesmente desabilitar a minificação de seu pacote angular de app desta forma (use new Bundle () em vez de ScriptBundle () no arquivo de configuração do pacote):

nirmal kumar
fonte
0

Adicione os serviços $ http, $ scope na função do controlador, às vezes, se eles estiverem ausentes, esses erros ocorrerão.

Omkar Dixit
fonte
0

Eu tive o mesmo problema, mas o problema era diferente, eu estava tentando criar um serviço e passar $ escopo para ele como um parâmetro.
Essa é outra maneira de obter esse erro, pois a documentação desse link diz:

A tentativa de injetar um objeto de escopo em qualquer coisa que não seja um controlador ou uma diretiva, por exemplo um serviço, também lançará um provedor desconhecido: $ scopeProvider <- $ erro de escopo. Isso pode acontecer se alguém registrar por engano um controlador como um serviço, por exemplo:

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.
}]);
Eugenio Miró
fonte