"Erreur non interceptée: [$ injector: un]" avec angulaire après le déploiement

97

J'ai une application Angular assez simple qui fonctionne très bien sur ma machine de développement, mais qui échoue avec ce message d'erreur (dans la console du navigateur) après son déploiement:

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

Aucun autre message à part ça. Cela se produit lorsque la page se charge pour la première fois.

J'exécute ASP.NET MVC5, Angular 1.2RC3 et je pousse vers Azure via git.

Google n'a rien trouvé d'intéressant.

Aucune suggestion?

ÉDITER:

J'utilise TypeScript et je définis mes dépendances avec la $injectvariable, par exemple:

export class DashboardCtrl {

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

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

Je crois que cela devrait (ou vise à) contourner les problèmes de changement de nom de variable locale qui surviennent lors de la minification et qui peuvent provoquer cette erreur.

Cela dit, cela a clairement quelque chose à voir avec le processus de minification, car lorsque je le configure BundleTable.EnableOptimizations = truesur ma machine de développement, je peux le reproduire.

Ken Smith
la source

Réponses:

163

Si vous suivez votre lien, cela vous indique que l'erreur résulte du fait que $ injector ne parvient pas à résoudre vos dépendances. C'est un problème courant avec angular lorsque le javascript est minifié / uglifié / quoi que vous lui fassiez pour la production.

Le problème est lorsque vous avez par exemple un contrôleur;

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

La minification change $scopeet $qdevient des variables aléatoires qui ne disent pas à angulaire quoi injecter. La solution est de déclarer vos dépendances comme ceci:

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

Cela devrait résoudre votre problème.

Juste pour répéter, tout ce que j'ai dit se trouve sur le lien que le message d'erreur vous fournit.

Stuart Nelson
la source
2
Merci pour la suggestion de visiter le lien - j'avais supposé que c'était un artefact interne, pas quelque chose à mon avantage. En fin de compte, je définis toutes mes dépendances via la $injectvariable publique, ce qui, je pense, équivaut à la façon dont vous suggérez (voir docs.angularjs.org/guide/di ). Je vais mettre à jour ma question.
Ken Smith
2
Cela dit, cela a clairement quelque chose à voir avec le processus de minification, car lorsque je force des minifications ASP.NET MVC sur ma machine de développement ( BundleTable.EnableOptimizations = true;), je peux reproduire le problème. Continuer à regarder.
Ken Smith
OK, je l'ai compris. Il y avait un autre endroit où je faisais de la DI que j'avais oublié, et ça se gâchait dans le processus de minification. Merci, c'était la bonne réponse.
Ken Smith
Il existe également un package qui gérera automatiquement cela pour vous appelé ngmin et un joyau correspondant pour Rails appelé ngmin-rails .
bradleygriffith
2
@RyanTuck - En d'autres termes, avec du code non réduit, Angular peut simplement regarder les noms de variables dans vos fonctions et faire une bonne estimation de ce qui doit être injecté. Mais avec le code minifié, les noms de variables sont tous mélangés, il a donc besoin d'un autre mécanisme - un mécanisme qui ne change pas lorsque le code est minifié - pour savoir quoi injecter. C'est là que le tableau $ inject et les autres mécanismes entrent en jeu.
Ken Smith
13

J'ai moi-même rencontré le même problème, mais mes définitions de contrôleur étaient un peu différentes de celles ci-dessus. Pour les contrôleurs définis comme ceci:

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

Ajoutez simplement une ligne après la déclaration indiquant les objets à injecter lorsque le contrôleur est instancié:

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

Cela le rend sûr pour la minification.

Mat
la source
11

Ce problème se produit lorsque le contrôleur ou la directive ne sont pas spécifiés en tant que tableau de dépendances et de fonction. Par exemple

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

Une fois minifié Le '$ scope' passé à la fonction de contrôleur est remplacé par un nom de variable à une seule lettre. Cela rendra angulaire ignorant de la dépendance. Pour éviter cela, transmettez le nom de la dépendance avec la fonction sous forme de tableau.

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

Si vous avez des fichiers séparés pour l'application angulaire \ resources \ directives et d'autres choses, vous pouvez simplement désactiver la minification de votre bundle d'applications angulaire comme ceci (utilisez new Bundle () au lieu de ScriptBundle () dans votre fichier de configuration de bundle):

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

Et l'application angulaire apparaîtrait dans le paquet non modifiée.

Schnapz
la source
À propos des performances, quel est le meilleur? Bundle () ou ScriptBundle ()?
Thomas.Benz
@ Thomas.Benz L'utilisation de Bundle () ne désactivera la minification que pour vos scripts. Le problème ici est que lorsque ScriptBundle () réduit certains scripts Angular, il raccourcit les noms de fonctions et fait d'autres choses connexes. Et quand Angular essaie de faire des injections de dépendances internes, ou quelque chose comme ça, il n'a pas pu trouver les fonctions appropriées pour cela, parce que leurs noms ont été modifiés de manière personnalisée (comme de «SuperController» à «s» ou autre). Il est donc préférable de laisser les scripts angulaires non modifiés ou d'essayer d'utiliser une autre bibliothèque pour la minification au lieu de celle par défaut.
Schnapz
1

Si vous avez des fichiers séparés pour l'application angulaire \ resources \ directives et d'autres choses, vous pouvez simplement désactiver la minification de votre bundle d'applications angulaire comme ceci (utilisez new Bundle () au lieu de ScriptBundle () dans votre fichier de configuration de bundle):

nirmal kumar
la source
0

Ajoutez les services $ http, $ scope dans la fonction du contrôleur, parfois s'ils manquent, ces erreurs se produisent.

Omkar Dixit
la source
0

J'ai eu le même problème mais le problème était différent, j'essayais de créer un service et de lui passer $ scope en tant que paramètre.
C'est une autre façon d'obtenir cette erreur comme le dit la documentation de ce lien:

Tenter d'injecter un objet scope dans tout ce qui n'est pas un contrôleur ou une directive, par exemple un service, lèvera également une erreur de fournisseur inconnu: $ scopeProvider <- $ scope error. Cela peut se produire si l'on enregistre par erreur un contrôleur en tant que service, par exemple:

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ó
la source