Quelle est la différence entre " @ " et " = " dans le champ d'application de la directive AngularJS?

j'ai lu attentivement la documentation D'AngularJS sur le sujet, puis j'ai trafiqué une directive. Voici le violon .

Et voici quelques extraits pertinents:

  • du HTML:

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
    
  • de la directive pane:

    scope: { biTitle: '=', title: '@', bar: '=' },
    

il y a plusieurs choses que je ne comprends pas:

  • Pourquoi dois-je utiliser "{{title}}" avec '@' et "title" avec '=' ?
  • puis-je également accéder à la portée parent directement, sans décorer mon élément d'un attribut?
  • la documentation dit " souvent il est souhaitable de passer des données de la portée isolée par une expression et à la portée de parent " , mais cela semble fonctionner très bien avec la reliure bidirectionnelle aussi. Pourquoi la voie de l'expression serait meilleure?

j'ai trouvé un autre violon qui montre aussi l'expression solution: http://jsfiddle.net/maxisam/QrCXh /

1003
demandé sur Pooja Kedar 2012-12-27 10:10:29

17 réponses

Pourquoi dois-je utiliser "{{titre}}" avec " @ et "titre" avec ' = '?

@ lie une propriété locale/directive à la valeur évaluée de L'attribut DOM . Si vous utilisez title=title1 ou title="title1" , la valeur de L'attribut DOM "title" est simplement la chaîne de caractères title1 . Si vous utilisez title="{{title}}" , la valeur de L'attribut DOM " title "est la valeur interpolée de {{title}} , donc la chaîne de caractères sera quelle que soit la propriété parent scope" title " est actuellement définie. Puisque les valeurs d'attribut sont toujours des chaînes de caractères, vous finirez toujours avec une valeur de chaîne pour cette propriété dans le champ d'application de la directive en utilisant @ .

= lie une propriété locale / directive à une propriété mère à . Donc, avec = , vous utilisez le nom de propriété Parent model/scope comme valeur de L'attribut DOM. Vous ne pouvez pas utiliser {{}} s avec = .

avec @, vous pouvez faire des choses comme title="{{title}} and then some" -- {{titre}} est interpolé, puis la chaîne" and them some " est concaténée avec elle. La chaîne concaténée finale est ce que la propriété local / directive scope obtient. (Vous ne pouvez pas faire cela avec = , seulement @ .)

avec @ , vous devrez utiliser attr.$observe('title', function(value) { ... }) si vous avez besoin d'utiliser la valeur dans votre fonction lien(ing). Par exemple, if(scope.title == "...") ne marchera pas comme vous l'attendez. Notez que cela signifie que vous ne pouvez accéder à cet attribut de façon asynchrone . Vous n'avez pas besoin d'utiliser $observer() si vous utilisez uniquement la valeur dans un modèle. Par exemple, template: '<div>{{title}}</div>' .

avec = , vous n'avez pas besoin d'utiliser $observer.

puis-je également accéder à la portée parent directement, sans décorer mon élément d'un attribut?

Oui, mais seulement si vous n'utilisez pas d'isolateur. Supprimer cette ligne de votre directive

scope: { ... }

et alors votre directive ne créera pas un nouveau champ d'application. Il utilisera le champ parent. Vous peut alors accéder directement à toutes les propriétés parent scope.

la documentation dit "souvent il est souhaitable de passer des données du champ isolé via une expression et au champ parent", mais cela semble fonctionner très bien avec la reliure bidirectionnelle aussi. Pourquoi la voie de l'expression serait meilleure?

Oui, bidirectionnel binding autorise le local / directive scope et le parent scope à partager des données. "L'Expression de liaison" permet à la directive d'appeler une expression (ou une fonction) définie par un attribut DOM -- et vous pouvez aussi passer des données comme arguments à l'expression ou à la fonction. Donc, si vous n'avez pas besoin de partager des données avec le parent -- vous voulez juste appeler une fonction définie dans le champ d'application parent -- vous pouvez utiliser la syntaxe & .

Voir aussi

1116
répondu Mark Rajcok 2017-05-23 10:31:37

il y a beaucoup de bonnes réponses ici, mais je voudrais offrir mon point de vue sur les différences entre @ , = , et & liant qui s'est avéré utile pour moi.

les trois liaisons sont des moyens de passer des données de votre champ parent au champ isolé de votre directive à travers les attributs de l'élément:

  1. @ la reliure est pour passer chaîne. Ces chaînes supportent les expressions {{}} pour les valeurs interpolées. Exemple: . L'expression interpolée est évaluée par rapport à champ d'application parent de la directive.

  2. = la reliure est pour la reliure de modèle bidirectionnelle. Le modèle de parent est lié au modèle du champ d'application isolé de la directive. Les changements de un modèle affecte l'autre, et vice versa.

  3. & liing est destiné à introduire une méthode dans le champ d'application de votre directive afin que il peut être appelé dans votre directive. La méthode est prédéfinie à la portée principale de la directive et les arguments à l'appui. Par exemple, si la méthode est bonjour(nom) portée parent, puis dans commande pour exécuter la méthode de l'intérieur de votre directive, vous devez appelons $champ d'application.bonjour ({nom:'Monde'})

je trouve qu'il est plus facile de se souvenir de ces différences en se référant aux reliures de portée par une description plus courte:

  • @ attribut chaîne liant
  • = les Deux sens de la liaison du modèle
  • & méthode de Rappel de liaison

les symboles le rendent aussi plus clair pour ce qui est de ce que la variable de champ d'application représente dans le cadre de la mise en œuvre de votre directive:

  • @ chaîne
  • = modèle
  • & méthode

Dans l'ordre de l'utilité (pour moi de toute façon):

  1. =
  2. @
  3. &
525
répondu pixelbits 2017-01-03 19:53:50

le = signifie liaison bidirectionnelle, donc une référence à une variable par rapport à la portée de base. Cela signifie que, lorsque vous modifiez la variable dans la directive, elle sera également modifiée dans le champ parent.

@ signifie que la variable sera copiée (clonée) dans la directive.

autant Que je sache, <pane bi-title="{{title}}" title="{{title}}">{{text}}</pane> devrait fonctionner aussi. bi-title recevra la valeur de la variable de champ parent, qui peut être modifiée dans la directive.

si vous devez changer plusieurs variables dans le champ parent, vous pouvez exécuter une fonction sur le champ parent à partir de la directive (ou transmettre des données via un service).

60
répondu asgoth 2017-01-03 19:53:43

si vous souhaitez voir plus comment cela fonctionne avec un exemple en direct. http://jsfiddle.net/juanmendez/k6chmnch /

var app = angular.module('app', []);
app.controller("myController", function ($scope) {
    $scope.title = "binding";
});
app.directive("jmFind", function () {
    return {
        replace: true,
        restrict: 'C',
        transclude: true,
        scope: {
            title1: "=",
            title2: "@"
        },
        template: "<div><p>{{title1}} {{title2}}</p></div>"
    };
});
36
répondu Juan Mendez 2015-04-13 06:59:40

@ get comme une chaîne de caractères

  • ceci ne crée aucune reliure. Vous obtenez simplement le mot que vous avez passé en tant que chaîne

= 2 Voie de liaison

  • les modifications apportées par le contrôleur seront reflétées dans la référence contenue dans la directive, et vice-versa

& cela se comporte un peu différemment, parce que le scope obtient une fonction qui renvoie l'objet qui a été passé dans . Je suppose que c'était nécessaire pour que ça marche. le violon devrait le dire clairement.

  • après avoir appelé cette fonction getter, l'objet résultant se comporte comme suit:
    • si une fonction a été passée: alors le la fonction est exécutée dans la fermeture parent (controller) lorsqu'elle est appelée
    • si une non-fonction a été passée: il suffit d'obtenir une copie locale de l'objet qui n'a pas de reliures



ce violon devrait montrer comment ils fonctionnent . Faites une attention particulière aux fonctions de portée avec get... dans le nom pour mieux comprendre ce que je veux dire à propos de &

35
répondu geg 2016-02-01 16:42:09

il y a trois façons d'ajouter le champ d'application dans la directive:

  1. Parent scope : c'est l'héritage par défaut de scope.

la directive et sa directive mère(contrôleur/directive à l'intérieur de laquelle elle se trouve) ont le même champ d'application. Ainsi, toute modification apportée aux variables scope à l'intérieur de la directive se reflète également dans le contrôleur parent. Vous n'avez pas besoin de spécifier ce que c'est la valeur par défaut.

  1. Child scope : la directive crée un scope enfant qui hérite du scope parent si vous spécifiez la variable scope de la directive comme vraie.

ici, si vous changez les variables scope à l'intérieur de la directive, cela ne se reflétera pas dans le champ d'application parent, mais si vous changez la propriété d'une variable scope, qui se reflète dans le champ d'application parent, comme vous avez modifié la variable scope du parent.

exemple,

app.directive("myDirective", function(){

    return {
        restrict: "EA",
        scope: true,
        link: function(element, scope, attrs){
            scope.somvar = "new value"; //doesnot reflect in the parent scope
            scope.someObj.someProp = "new value"; //reflects as someObj is of parent, we modified that but did not override.
        }
    };
});
  1. Isolated scope : ceci est utilisé lorsque vous voulez créer le scope qui n'hérite pas du scope du controller.

cela se produit lorsque vous créez des plugins car cela rend la directive générique puisqu'elle peut être placée dans N'importe quel HTML et n'est pas affectée par son champ d'application parent.

maintenant, si vous ne voulez pas d'interaction avec le parent, alors vous pouvez simplement spécifier l'étendue comme un objet vide. comme,

scope: {} //this does not interact with the parent scope in any way

la plupart du temps ce n'est pas le cas car nous avons besoin d'une certaine interaction avec la portée parente, donc nous voulons que certaines des valeurs/ changements passent à travers. Pour cette raison, nous utilisons:

1. "@"   (  Text binding / one-way binding )
2. "="   ( Direct model binding / two-way binding )
3. "&"   ( Behaviour binding / Method binding  )

@ cela signifie que les modifications du champ d'application du contrôleur seront reflétées dans le champ d'application de la directive, mais si vous modifiez la valeur dans le champ d'application de la directive, le la variable Controller scope ne sera pas affectée.

@ s'attend toujours à ce que l'attribut mappé soit une expression. C'est très important, car pour que le préfixe "@" fonctionne, nous devons envelopper la valeur de l'attribut à l'intérieur de {{}}.

= est bidirectionnel donc si vous changez la variable dans le champ d'application de la directive, la variable de champ d'application du contrôleur est aussi affectée

& est utilisé pour lier controller scope method de sorte que si nécessaire, nous pouvons l'appeler à partir de la directive

l'avantage ici est que le nom de la variable ne doit pas nécessairement être le même dans le champ d'application du contrôleur et de la directive.

exemple, le champ d'application de la directive a une variable "dirVar" qui se synchronise avec la variable "contVar" du champ d'application du contrôleur. Cela donne beaucoup de puissance et de généralisation à la directive car un contrôleur peut se synchroniser avec la variable v1 tandis qu'un autre contrôleur utilisant la la même directive peut demander à dirVar de se synchroniser avec la variable v2.

ci-dessous est l'exemple d'usage:

la directive et le contrôleur sont:

 var app = angular.module("app", []);
 app.controller("MainCtrl", function( $scope ){
    $scope.name = "Harry";
    $scope.color = "#333333";
    $scope.reverseName = function(){
     $scope.name = $scope.name.split("").reverse().join("");
    };
    $scope.randomColor = function(){
        $scope.color = '#'+Math.floor(Math.random()*16777215).toString(16);
    };
});
app.directive("myDirective", function(){
    return {
        restrict: "EA",
        scope: {
            name: "@",
            color: "=",
            reverse: "&"
        },
        link: function(element, scope, attrs){
           //do something like
           $scope.reverse(); 
          //calling the controllers function
        }
    };
});

et le html (notez la différence pour @ et =):

<div my-directive
  class="directive"
  name="{{name}}"
  reverse="reverseName()"
  color="color" >
</div>

voici un lien vers le blog qui le décrit bien.

32
répondu Kop4lyf 2017-11-07 08:36:07

simplement nous pouvons utiliser: -

  1. @ :- pour les valeurs de Chaîne de liaison de Données. dans un sens data binding vous ne pouvez passer valeur de champ d'application à la directive

  2. = :- pour la valeur de l'objet pour les deux sens de la liaison de données. en liant les données de deux façons, vous pouvez changer la valeur de champ d'application dans la directive aussi bien que dans html aussi.

  3. & :- pour les méthodes et les fonctions.

EDIT

Dans notre Composant définition de Angulaire de la version 1.5 Et au-dessus de

il existe quatre types différents de reliures:

  1. = liaison de données bidirectionnelle : - si nous modifions la valeur,elle se met automatiquement à jour
  2. < une façon de lier : - quand nous voulons simplement lire un paramètre d'un scope parent et ne pas le mettre à jour.

  3. @ c'est pour paramètres de chaîne de caractères

  4. & c'est pour Callbacks dans le cas où votre composant a besoin de sortir quelque chose à sa portée parent

20
répondu ojus kulkarni 2017-05-15 04:55:46

j'ai créé un petit fichier HTML qui contient du code angulaire démontrant les différences entre eux:

<!DOCTYPE html>
<html>
  <head>
    <title>Angular</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="myCtrl as VM">
      <a my-dir
        attr1="VM.sayHi('Juan')" <!-- scope: "=" -->
        attr2="VM.sayHi('Juan')" <!-- scope: "@" -->
        attr3="VM.sayHi('Juan')" <!-- scope: "&" -->
      ></a>
    </div>
    <script>
    angular.module("myApp", [])
    .controller("myCtrl", [function(){
      var vm = this;
      vm.sayHi = function(name){
        return ("Hey there, " + name);
      }
    }])
    .directive("myDir", [function(){
      return {
        scope: {
          attr1: "=",
          attr2: "@",
          attr3: "&"
        },
        link: function(scope){
          console.log(scope.attr1);   // =, logs "Hey there, Juan"
          console.log(scope.attr2);   // @, logs "VM.sayHi('Juan')"
          console.log(scope.attr3);   // &, logs "function (a){return h(c,a)}"
          console.log(scope.attr3()); // &, logs "Hey there, Juan"
        }
      }
    }]);
    </script>
  </body>
</html>
11
répondu RobertAKARobin 2018-07-17 15:41:23

Le = , c'est "la 151910920" 2-way "liaison de 151920920" , qui vous permet d'avoir live les changements à l'intérieur de votre directive. Quand quelqu'un change cette variable hors de la directive, vous aurez que les données modifiées dans votre directive, mais @ chemin n'est pas liant dans les deux sens . Il fonctionne comme texte . Vous liez une fois, et vous aurez seulement sa valeur.

Pour l'obtenir plus clairement, vous pouvez utiliser ce grand article:

directive AngularJS champ d'application '@' et ' = '

6
répondu Hazarapet Tunanyan 2016-07-09 14:17:25

@ la propriété local scope est utilisée pour accéder aux valeurs des chaînes qui sont définies en dehors de la directive.

= dans les cas où vous devez créer une liaison bidirectionnelle entre le champ extérieur et le champ isolé de la directive, vous pouvez utiliser le caractère=.

& la propriété de portée locale permet au consommateur d'une directive de passer dans une fonction que la directive peut invoquer.

veuillez vérifier le lien ci-dessous qui vous donne une compréhension claire avec des exemples.J'ai trouvé ça très utile, alors j'ai pensé à le partager.

http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope

3
répondu Raphael 2016-02-05 15:50:27

j'ai implémenté toutes les options possibles dans un violon.

il traite de toutes les options:

scope:{
    name:'&'
},

scope:{
    name:'='
},

scope:{
    name:'@'
},

scope:{

},

scope:true,

https://jsfiddle.net/rishulmatta/v7xf2ujm

3
répondu Rishul Matta 2016-05-17 14:55:27

même si la portée est locale, comme dans votre exemple, vous pouvez accéder à la portée mère par la propriété $parent . Supposons dans le code ci-dessous que title est défini sur le champ d'application parent. Vous pouvez alors accéder au titre comme $parent.title :

link : function(scope) { console.log(scope.$parent.title) },
template : "the parent has the title {{$parent.title}}"

cependant, dans la plupart des cas, le même effet est mieux obtenu en utilisant des attributs.

un exemple d'où j'ai trouvé le " & " notation, qui est utilisé "pour transmettre des données à partir de la portée isolée via une expression et de la portée parent", utile (et dans les deux sens de la liaison de données ne peut pas être utilisé) a été dans une directive pour le rendu spécial discbased à l'intérieur d'une ng-repeat.

<render data = "record" deleteFunction = "dataList.splice($index,1)" ng-repeat = "record in dataList" > </render>

une partie du rendu était un bouton Supprimer et ici il était utile d'attacher un deletefunction à partir de la portée extérieure via &. Dans la directive render, on dirait

scope : { data = "=", deleteFunction = "&"},
template : "... <button ng-click = "deleteFunction()"></button>"

la liaison de données bidirectionnelle, c'est-à-dire data = "=" ne peut pas être utilisée comme fonction de suppression fonctionnerait sur chaque cycle $digest , ce qui n'est pas bon, car l'enregistrement est alors immédiatement supprimé et jamais rendu.

2
répondu user3750988 2015-12-02 22:19:29

@ et = voir les autres réponses.

One gotcha about &

TL; DR;

& obtient expression (pas seulement fonction comme dans les exemples dans d'autres réponses) d'un parent, et la définit comme une fonction dans la directive, qui appelle l'expression. Et cette fonction a le possibilité de remplacer n'importe quelle variable (même nom de fonction) d'expression, en passant un objet avec les variables.

expliquée

& est une référence d'expression, cela signifie que si vous passez quelque chose comme <myDirective expr="x==y"></myDirective>

dans la directive CE expr sera une fonction, qui appelle l'expression, comme:

function expr(){return x == y} .

ainsi, dans la directive html <button ng-click="expr()"></button> appellera l'expression. Dans js de la directive juste $scope.expr() appellera l'expression aussi.

L'expression sera appelée avec $scope.x $et la portée.y de la mère.

Vous avez la possibilité d'outrepasser les paramètres!

Si vous les définissez par appel, par exemple <button ng-click="expr({x:5})"></button>

ensuite, l'expression sera appelée avec en paramètre x et paramètre parent y .

Vous pouvez outrepasser les deux.

Maintenant, vous savez pourquoi <button ng-click="functionFromParent({x:5})"></button> .

Parce qu'il appelle simplement l'expression de parent (par exemple <myDirective functionFromParent="function1(x)"></myDirective> ) et remplace les valeurs possibles par vos paramètres spécifiés, dans ce cas x .

il pourrait être:

<myDirective functionFromParent="function1(x) + 5"></myDirective>

ou

<myDirective functionFromParent="function1(x) + z"></myDirective>

avec appel d'enfant:

<button ng-click="functionFromParent({x:5, z: 4})"></button> .

ou même avec un remplacement de fonction:

<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button> .

ce n'est qu'une expression, peu importe si c'est une fonction, ou plusieurs fonctions, ou juste une comparaison. Et vous pouvez remplacer n'importe quelle variable de cette expression.

exemples:

modèle de directive vs appelé code:

parent a défini $scope.x, $champ d'application.y:

modèle de parent: <myDirective expr="x==y"></myDirective>

<button ng-click="expr()"></button> appels $scope.x==$scope.y

<button ng-click="expr({x: 5})"></button> appels 5 == $scope.y

<button ng-click="expr({x:5, y:6})"></button> appels 5 == 6

parent a défini $portée.fonction1, $champ d'application.x, $champ d'application.y:

modèle parent: <myDirective expr="function1(x) + y"></myDirective>

<button ng-click="expr()"></button> calls $scope.function1($scope.x) + $scope.y

<button ng-click="expr({x: 5})"></button> appels $scope.function1(5) + $scope.y

<button ng-click="expr({x:5, y:6})"></button> appels $scope.function1(5) + 6

la directive a une portée.myFn as function:

<button ng-click="expr({function1: myFn, x:5, y:6})"></button> appels $scope.myFn(5) + 6

1
répondu ya_dimon 2017-11-16 18:56:09

la principale différence entre eux est juste

@ Attribute string binding
= Two-way model binding
& Callback method binding
1
répondu Ashish Kamble 2018-05-31 09:51:56

Pourquoi dois-je utiliser "{{titre}}" par " @ " et "titre" par"="?

lorsque vous utilisez {{titre}}, seule la valeur de champ parent sera transmise à la vue directive et évaluée. Cela se limite à une seule façon, ce qui signifie que le changement ne se reflétera pas dans la portée des parents. Vous pouvez utiliser ' = ' lorsque vous voulez refléter les changements apportés dans la directive child au champ d'application parent également. C'est de deux.

puis - je également accédez directement à la portée parent, sans décorer mon élément avec un attribut?

lorsque la directive comporte l'attribut scope (scope: {}), vous ne pourrez plus accéder directement au champ parent. Mais il est tout de même possible d'y accéder via scope.$ parent etc. Si vous supprimez le champ d'application de la directive, vous pouvez y accéder directement.

la documentation dit" souvent, il est souhaitable de transmettre des données à partir de la isolé scope via une expression et au scope parent", mais que semble bien fonctionner avec une liaison bidirectionnelle. Pourquoi l' l'expression de la route de mieux?

cela dépend du contexte. Si vous voulez appeler une expression ou une fonction avec des données, vous utilisez & et si vous voulez partager des données , vous pouvez utiliser biderectional way en utilisant ' = '

vous pouvez trouver les différences entre les multiples façons de passer des données à la directive à lien ci-dessous:

AngularJS-Isolated Scopes - @ vs = vs &

http://www.codeforeach.com/angularjs/angularjs-isolated-scopes-vs-vs

0
répondu Prashanth - codeforeach.com 2017-06-28 09:11:54

@ Attribut de chaîne de liaison (d'une manière) = Liaison bidirectionnelle du modèle Et de la méthode de rappel de liaison

0
répondu Jatin Patel 2017-11-13 05:39:41

@ lie une propriété locale/directive à la valeur évaluée de L'attribut DOM. = lie une propriété locale / directive scope à une propriété scope mère. & binding est pour passer une méthode dans le champ d'application de votre directive afin qu'elle puisse être appelée dans votre directive.

@ attribut string binding = Liaison bidirectionnelle du modèle Et de la méthode de rappel de liaison

0
répondu Ashish Kamble 2018-06-18 06:36:16