web-dev-qa-db-fra.com

Pourquoi mes directives AngularJS partagent-elles le même champ d'application?

J'ai essayé de faire une directive simple qui affiche un nom et lui permet de changer. Lorsque je mets plusieurs directives sur la page de noms, elles semblent toutes partager l'attribut de nom. Qu'est-ce que je fais mal?

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset=utf-8 />
<title></title>

  <script src="http://code.angularjs.org/1.2.0-rc.3/angular.min.js"></script>
  <script src="http://code.angularjs.org/1.2.0-rc.3/angular-resource.min.js"></script>
  <script src="http://code.angularjs.org/1.2.0-rc.3/angular-animate.min.js"></script>
  <script>
    var app = angular.module('app', []);

    app.directive('person', function () {

    function link ($scope, elem, attrs, ctrl) {     

        $scope.name = "OLD"        

        $scope.setName = function() {
            $scope.name = 'NEW';
        }
    }

    return {
      restrict: 'E',
      replace: true,
      template: "<span>Current name = {{name}}<a href='' class='btn' ng-click='setName()'>Change name</a><br></span>",
      link : link,
    }

  });

  app.controller('MainCtrl', function ($scope) { });

  </script>    

</head>

<body ng-controller='MainCtrl'>
  <person></person><br>
  <person></person><br>
  <person></person><br>
  <person></person><br>
</body>

</html>
15
nickponline

Comme indiqué dans les réponses précédentes, le comportement par défaut des directives AngularJS consiste à partager la portée dans laquelle elles sont incluses. Ce comportement est modifié via le paramètre scope dans l'objet de définition de directive.

Vous pouvez afficher la documentation relative à l'argument scope dans cette section des documents AngularJS: http://docs.angularjs.org/api/ng.$compile#description_comprehensive-directive-api_directive-definition-object

Cet argument a trois options:

  1. scope: false - comportement par défaut de partage de la portée dans laquelle la directive est incluse

  2. scope: true - crée une nouvelle portée pour la directive qui agit comme les autres portées enfants et hérite de manière prototypique de la portée parente

  3. scope: {} - crée une portée isolée qui n'hérite pas de manière prototypique de sa portée parent

Comme vous pouvez le voir avec les exemples JSBin, les options 2 et 3 fonctionneront pour votre exemple. La différence est de savoir si vous voulez que vos nouvelles étendues soient isolées ou non.

La section sur les directives du guide AngularJS contient une bonne section sur les raisons pour lesquelles une portée isolée peut aider à créer de meilleurs modules réutilisables avec des directives: Guide AngularJS: Isoler la portée d’une directive

33
Stokes Player

Par défaut, si vous n'isolez pas la portée d'une directive, vous partagerez la portée "externe" avec toutes les instances de votre directive personne. Avec votre implémentation actuelle, vous devez créer un contrôleur différent à chaque fois pour pouvoir réutiliser une telle directive.

MAIS il y a une solution à cette faille et elle s’appelle isolate scope. Pour ce faire, vous pouvez utiliser l'option de portée d'une directive comme suit:

return {
  restrict: 'E',
  replace: true,
  scope : {}, // this is where the magic happens
  template: "<span>Current name = {{name}}<a href='' class='btn' ng-click='setName()'>Change name</a><br></span>",
  link : link,
}

Vous avez un exemple complet et une explication sur ici section Isoler le champ d'application d'une directive

3
Nicolas ABRIC

Par défaut, les directives partagent la même portée. Mais si nécessaire, vous pouvez utiliser scope isolé pour vos directives: utilisez scope: {} comme champ dans la définition de votre directive.

app.directive('person', function () {

    function link ($scope, elem, attrs, ctrl) {     

        $scope.name = "OLD"        

        $scope.setName = function() {
            $scope.name = 'NEW';
        }
    }

    return {
      restrict: 'E',
      scope: {}
      replace: true,
      template: "<span>Current name = {{name}}<a href='' class='btn' ng-click='setName()'>Change name</a><br></span>",
      link : link,
    }

  });
2
Stephane Rolland

Vous avez 3 options pour scope dans les directives AngularJS

  1. false (Utilise la portée parent)
  2. true (crée sa propre portée et hérite également du parent, c.-à-d. que vous pouvez également accéder aux éléments définis dans la portée du parent)
  3. {} (crée une portée isolée)

 AngularJS Directives scope option

Me laisser démontrer ceci en utilisant $ rootScope

    app.run(function($rootScope){
      $rootScope.firstname = "Root scope name";
      $rootScope.rootValue = "Root value";
    });

    app.directive("sampleDirective",function(){
      return{
        template:"<div>{{firstname}}{{rootValue}}</div>",
 // here rootValue will be accessible as its inherited from parent. You can overwrite this as well
        scope : true,
        controller:['$scope',sampleDirectiveScope]
      };
    });

    function sampleDirectiveScope($scope){
      $scope.firstname = "child scope changing name - ";
    };

    app.directive("isolatedScopeDirective",function(){
      return {
        controller:isolatedFunction,
        template:" this has isolated scope ,<div>{{rootValue}}</div>", 
    // here rootValue will not be accessible because it is isolated and not inheriting from parent
        scope: {}
      };
    });

    function isolatedFunction($scope){ 
      //define values for this scope
    };

Cochez cette démo en direct

1
Vignesh Subramanian