"Error no detectado: [$ inyector: unpr]" con angular después de la implementación

97

Tengo una aplicación Angular bastante simple que se ejecuta bien en mi máquina de desarrollo, pero falla con este mensaje de error (en la consola del navegador) después de implementarlo:

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

Ningún otro mensaje además de ese. Sucede cuando se carga la página por primera vez.

Estoy ejecutando ASP.NET MVC5, Angular 1.2RC3 y presionando a Azure a través de git.

Buscar en Google no ha encontrado nada interesante.

¿Alguna sugerencia?

EDITAR:

Estoy usando TypeScript y definiendo mis dependencias con la $injectvariable, por ejemplo:

export class DashboardCtrl {

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

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

Creo que debería (o tiene la intención de) solucionar los problemas de cambio de nombre de las variables locales que surgen durante la minificación y que pueden causar este error.

Dicho esto, claramente tiene algo que ver con el proceso de minificación, ya que cuando lo configuro BundleTable.EnableOptimizations = trueen mi máquina de desarrollo, puedo reproducirlo.

Ken Smith
fuente

Respuestas:

163

Si sigue su enlace, le indicará que el error se debe a que $ injector no puede resolver sus dependencias. Este es un problema común con angular cuando el javascript se minimiza / uglified / lo que sea que esté haciendo para la producción.

El problema es cuando tiene, por ejemplo, un controlador;

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

La minificación cambia $scopey se convierte $qen variables aleatorias que no le dicen a angular qué inyectar. La solución es declarar sus dependencias así:

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

Eso debería arreglar tu problema.

Solo para reiterar, todo lo que he dicho está en el enlace que le proporciona el mensaje de error.

Stuart Nelson
fuente
2
Gracias por la sugerencia de visitar el enlace; asumí que era un artefacto interno, no algo para mi beneficio. Resulta que estoy definiendo todas mis dependencias a través de la $injectvariable pública, que creo que es equivalente a la forma en que sugieres (consulta docs.angularjs.org/guide/di ). Actualizaré mi pregunta.
Ken Smith
2
Dicho esto, claramente tiene algo que ver con el proceso de minificación, ya que cuando fuerzo las minificaciones de ASP.NET MVC en mi máquina de desarrollo ( BundleTable.EnableOptimizations = true;), puedo reproducir el problema. Continuando mirando.
Ken Smith
OK, lo descubrí. Había otro lugar en el que estaba haciendo DI que me había olvidado, y se estaba estropeando en el proceso de minificación. Gracias, esta fue la respuesta correcta.
Ken Smith
También hay un paquete que se encargará automáticamente de esto llamado ngmin y una gema correspondiente para Rails llamada ngmin-rails .
bradleygriffith
2
@RyanTuck: en otras palabras, con el código no minificado, Angular puede simplemente mirar los nombres de las variables en sus funciones y hacer una buena conjetura sobre lo que debe inyectarse. Pero con el código minimizado, los nombres de las variables están todos modificados, por lo que necesita algún otro mecanismo, un mecanismo que no cambia cuando el código se minimiza, para saber qué inyectar. Ahí es donde entran en juego la matriz $ inject y los otros mecanismos.
Ken Smith
13

Me encontré con el mismo problema, pero las definiciones de mi controlador se veían un poco diferentes a las anteriores. Para controladores definidos así:

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

Simplemente agregue una línea después de la declaración que indique qué objetos inyectar cuando se crea una instancia del controlador:

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

Esto lo hace seguro para la minificación.

Mate
fuente
11

Este problema ocurre cuando el controlador o la directiva no se especifican como una matriz de dependencias y funciones. Por ejemplo

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

Cuando se minimiza El '$ scope' pasado a la función del controlador se reemplaza por un nombre de variable de una sola letra. Esto hará que angular no tenga ni idea de la dependencia. Para evitar esto, pase el nombre de la dependencia junto con la función como una matriz.

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

Si ha separado archivos para aplicaciones angulares \ recursos \ directivas y otras cosas, entonces puede deshabilitar la minificación de su paquete de aplicaciones angulares de esta manera (use el nuevo Bundle () en lugar de ScriptBundle () en el archivo de configuración de su paquete):

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

Y la aplicación angular aparecería en un paquete sin modificaciones.

Schnapz
fuente
Sobre el rendimiento, ¿cuál es mejor? ¿Paquete () o ScriptBundle ()?
Thomas.Benz
@ Thomas.Benz El uso de Bundle () solo desactivará la minificación de sus scripts. El problema aquí es que cuando ScriptBundle () minimiza algunos scripts angulares, acorta los nombres de las funciones y hace otras cosas relacionadas. Y cuando Angular intenta hacer algunas inyecciones de dependencia interna, o algo así, no pudo encontrar las funciones adecuadas para eso, porque sus nombres se cambiaron de manera personalizada (como de 'SuperController' a 's' o más). Por lo tanto, es mejor dejar los scripts angulares sin modificar o intentar usar alguna otra biblioteca para la minificación en lugar de la predeterminada.
Schnapz
1

Si ha separado archivos para aplicaciones angulares \ recursos \ directivas y otras cosas, entonces puede deshabilitar la minificación de su paquete de aplicaciones angulares de esta manera (use el nuevo Bundle () en lugar de ScriptBundle () en el archivo de configuración de su paquete):

nirmal kumar
fuente
0

Agregue los servicios $ http, $ scope en la función del controlador; a veces, si faltan, se producen estos errores.

Omkar Dixit
fuente
0

Tuve el mismo problema, pero el problema era diferente, estaba tratando de crear un servicio y pasarle $ scope como parámetro.
Esa es otra forma de obtener este error como dice la documentación de ese enlace:

Intentar inyectar un objeto de alcance en cualquier cosa que no sea un controlador o una directiva, por ejemplo, un servicio, también arrojará un proveedor Desconocido: $ scopeProvider <- $ scope error. Esto puede suceder si uno registra por error un controlador como servicio, por ejemplo:

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ó
fuente