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>
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:
scope: false
- comportement par défaut de partage de la portée dans laquelle la directive est incluse
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
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
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
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,
}
});
Vous avez 3 options pour scope
dans les directives AngularJS
false
(Utilise la portée parent)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){}
(crée une portée isolée)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