web-dev-qa-db-fra.com

Contrôleurs AngularJS et "use strict"

J'ai récemment commencé à utiliser JSHint et cela m'oblige à utiliser la forme de fonction "use strict". Depuis lors, AngularJS lance une erreur:

"Erreur: l'argument 'webAddressController' n'est pas une fonction, n'est pas défini"

Lorsque je supprime la forme de fonction "utiliser strictement", le contrôleur se charge correctement.

Contrôleur:

(function () {
    "use strict";

    function webAddressController($scope, $rootScope, web_address_service) {
             // Do things
    }

}());

Quelqu'un a-t-il une idée de ce qui se passe ici?

28
Chris Bier

Tout d'abord, je tiens à dire que pkozlowski connaît vraiment ses trucs à Angular, mais ce n'est pas vraiment un problème Angular) que c'est un problème de fermeture.

Angular recherche des contrôleurs à deux endroits:

  1. dans son propre registre de contrôleurs enregistrés via Module.controller ()
  2. Dans une variable globale (ou déclaration de fonction globale)

Le problème est que tout ce qui se trouve à l'intérieur de votre fermeture pour une "utilisation stricte" n'est pas global. Il est enveloppé et privatisé dans la fonction anonyme qui le contient.

(function() {
   // nothing in here is global or even public.
   // "use strict" or not.

   "use strict"; // this is mostly irrelevant.

   // this will not work, because it's wrapped and not global
   function ThisDoesntWork($scope) {
   };

   // window is the global root variable. So this works.
   window.ThisWorks = function($scope) {

   };

   // this will work, because it's explicitly registering the controller
   // presuming app is your Module variable from outside of the closure.
   app.controller('ThisIsBest', function($scope) {

   });

})();

//this works because it's global.
function ThisAlsoWorks($scope) {

}

// if you declare a global var, then set it inside
// of your closure, you're good to go too.
var ThisWillWorkToo;

(function {
    //here we're setting it again.
    ThisWillWorkToo = function($scope) {
    };
})();


// if you're really crazy you can even do this...
 var ThisWillWorkButItsWeird = (function() {
      "use strict";

       function ThisWillWorkButItsWeird($scope) {

       }

       return ThisWillWorkButItsWeird;
  })();

À la fin de la journée, vous pouvez mettre "use strict" dans n'importe quelle fonction, ou au niveau du fichier si vous le souhaitez. "use strict" lui-même ne rompt rien pour vous. Il y a mille façons d'enregistrer un contrôleur, comme vous pouvez le voir. Le meilleur choix est probablement de simplement les enregistrer explicitement avec la méthode .controller comme suggéré.

44
Ben Lesh

Je suppose que JSHint essaie de vous dire ici que c'est d'éviter les variables globales (ce qui est évidemment une très bonne pratique!).

AngularJS a une opinion légèrement différente sur la résolution du même problème (c'est-à-dire - éviter les variables globales) et vous permet de définir des contrôleurs dans les modules (en utilisant un espace de noms global angular). Vous pouvez réécrire votre exemple en utilisant des modules comme celui-ci:

angular.module('myApp',[]).controller('webAddressController', function($scope) {
    // Do things
});

Voici le jsFiddle illustrant cela en pratique: http://jsfiddle.net/t3vBE/1/

Avec cette approche, vous ne polluez pas l'espace de noms global avec des constructeurs de contrôleurs.

Vous devrez modifier la configuration JSHint pour autoriser la variable globale angular si vous souhaitez utiliser le mode strict. Alternativement, vous pouvez également envelopper votre code entier (encore une fois, en utilisant des modules) dans une fonction qui est exécutée immédiatement:

(function () {
    "use strict";

angular.module('myApp',[]).controller('webAddressController', function($scope) {

    $scope.name = 'World';
    // Do things
});

}());​

Voici le jsFiddle: http://jsfiddle.net/t3vBE/4/

Pour moi, cela n'a de sens que si vous voulez définir du JavaScript pur, des fonctions "d'assistance", sinon je ferais appel aux services AngularJS.

14

Une autre façon de faire ce que fait @pkzolowski si votre module angular est déjà chargé ailleurs:

var app = angular.module('myApp');
app.controller(...);
app.service(...);
...

Il est basé sur le commentaire d'ici: angularjs définissant les services pour le même module dans différents fichiers

Attention, l'utilisation d'angular.module ('myModule', []) créera le module myModule et écrasera tout module existant nommé myModule. Utilisez angular.module ('myModule') pour récupérer un module existant.

4
zeusstl

Avez-vous essayé d'écrire "use strict" à l'extérieur et avant (function ()

"use strict"; // <-- add it here
(function () {
    //"use strict"; <-- remove from here

    function webAddressController($scope, $rootScope, web_address_service) {
         // Do things
    }

}());

Ma réponse est basée sur les fichiers que j'ai vus générés par Yeoman

2
Siddhesh T