web-dev-qa-db-fra.com

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

J'ai lu attentivement la documentation d'AngularJS sur le sujet, puis j'ai bricolé avec une directive. Voici le violon .

Et voici quelques extraits pertinents:

  • Du HTML:

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

    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 directement à la portée parente sans décorer mon élément avec un attribut?
  • La documentation indique "Il est souvent souhaitable de transmettre des données de la portée isolée via une expression et à la portée parente", mais cela semble également fonctionner correctement avec la liaison bidirectionnelle. Pourquoi la voie d'expression serait-elle meilleure?

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

1025
iwein

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

@ lie une propriété de portée 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 title1. Si vous utilisez title="{{title}}", la valeur de l'attribut DOM "title" est la valeur interpolée de {{title}}; par conséquent, la chaîne correspond à la propriété parent "title" actuellement définie. Étant donné que les valeurs d'attribut sont toujours des chaînes, vous obtiendrez toujours une valeur de chaîne pour cette propriété dans la portée de la directive lorsque vous utilisez @.

= lie une propriété de portée locale/directive à une propriété de portée parent. Ainsi, avec =, vous utilisez le nom de la propriété modèle/portée parent 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" - {{title}} est interpolé, puis la chaîne "and them some" est concaténée avec elle. La chaîne concaténée finale correspond à ce que la propriété de portée locale/directive obtient. (Vous ne pouvez pas faire cela avec =, seulement @.)

Avec @, vous devrez utiliser attr.$observe('title', function(value) { ... }) si vous devez utiliser la valeur dans votre fonction link (ing). Par exemple, if(scope.title == "...") ne fonctionnera pas comme prévu. Notez que cela signifie que vous ne pouvez accéder à cet attribut de manière asynchrone . Vous n'avez pas besoin d'utiliser $ observe () si vous utilisez uniquement la valeur d'un modèle. Par exemple, template: '<div>{{title}}</div>'.

Avec =, vous n'avez pas besoin d'utiliser $ observe.

Puis-je également accéder directement à la portée parente sans décorer mon élément avec un attribut?

Oui, mais uniquement si vous n'utilisez pas une portée isolée. Supprimer cette ligne de votre directive 

scope: { ... } 

et alors votre directive ne créera pas de nouvelle portée. Il utilisera la portée parente. Vous pouvez ensuite accéder directement à toutes les propriétés de la portée parent.

La documentation indique "Il est souvent souhaitable de transmettre des données de la portée isolée via une expression et à la portée parent", mais cela semble également fonctionner correctement avec la liaison bidirectionnelle. Pourquoi la voie d'expression serait-elle meilleure?

Oui, la liaison bidirectionnelle permet à la portée locale/directive et à la portée parent de partager des données. "Liaison d'expression" permet à la directive d'appeler une expression (ou une fonction) définie par un attribut DOM. Vous pouvez également transmettre des données en tant qu'arguments à l'expression ou à la fonction. Ainsi, si vous n'avez pas besoin de partager des données avec le parent (vous souhaitez simplement appeler une fonction définie dans la portée du parent), vous pouvez utiliser la syntaxe &.

Voir également

1127
Mark Rajcok

Il y a beaucoup de bonnes réponses ici, mais j'aimerais offrir mon point de vue sur les différences entre les liaisons @, = et & qui m'ont été utiles.

Ces trois liaisons permettent de transmettre des données de votre portée parent à la portée isolée de votre directive via les attributs de l'élément:

  1. @ binding est pour le passage de chaînes. Ces chaînes supportent les expressions {{}} pour les valeurs interpolées. Par exemple: . L'expression interpolée est évaluée par rapport à portée parent de la directive.

  2. = La liaison est destinée à la liaison de modèle bidirectionnelle. Le modèle dans la portée parente est lié au modèle dans le champ d'application isolé de la directive. Changements en un modèle affecte l'autre, et vice versa.

  3. & binding permet de passer une méthode dans le champ d'application de votre directive de sorte que il peut être appelé dans votre directive. La méthode est pré-liée à portée parent de la directive et supporte les arguments. Par exemple, si la méthode est hello (nom) dans la portée du parent, puis dans Afin d’exécuter la méthode depuis votre directive, vous devez appelez $ scope.hello ({name: 'world'})

Je trouve qu'il est plus facile de se rappeler ces différences en se référant aux liaisons de la portée par une description plus courte:

  • @Chaîne d'attribut
  • =Liaison de modèle à deux voies
  • &Liaison de méthode de rappel

Les symboles indiquent également plus clairement ce que la variable scope représente dans la mise en œuvre de votre directive:

  • @string
  • =model
  • &méthode

Par ordre d’utilité (pour moi en tout cas):

  1. =
  2. @
  3. Et
531
pixelbits

Le = signifie une liaison bidirectionnelle, donc une référence à une variable de la portée parente. Cela signifie que lorsque vous modifiez la variable dans la directive, elle sera également modifiée dans la portée parente.

@ 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 aussi fonctionner. bi-title recevra la valeur de la variable de portée parent, qui peut être modifiée dans la directive.

Si vous devez modifier plusieurs variables dans la portée parente, vous pouvez exécuter une fonction sur la portée parente depuis la directive (ou transmettre des données via un service).

62
asgoth

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>"
    };
});
39
Juan Mendez

@get as string

  • Cela ne crée aucune liaison que ce soit. Vous obtenez simplement le mot que vous avez transmis sous forme de chaîne

=liaison à 2 voies

  • les modifications apportées par le responsable du traitement seront reflétées dans la référence détenue par la directive, et inversement

& Cela se comporte un peu différemment, car la portée obtient une fonction qui retourne l'objet qui a été passé dans. Je suppose que cela était nécessaire pour que cela fonctionne. _ {Le violon devrait le préciser.

  • Après avoir appelé cette fonction d'accesseur en lecture, l'objet obtenu se comporte comme suit:
    • si un fonction a été passé: alors la fonction est exécutée dans la fermeture du parent (contrôleur) lorsqu'elle est appelée
    • si un non-fonction a été passé: obtenez simplement une copie locale de l'objet qui n'a pas de liaisons


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

36
geg

La directive peut être ajoutée de trois manières différentes:

  1. Parent scope: il s'agit de l'héritage de la portée par défaut. 

La directive et son parent (contrôleur/directive dans lequel il se trouve) la portée est identique . Ainsi, toute modification apportée aux variables de portée de la directive est également reflétée dans le contrôleur parent. Vous n'avez pas besoin de spécifier ceci car c'est la valeur par défaut.

  1. Child scope: directive crée une portée enfant qui hérite de la portée parent si vous spécifiez la variable de portée de la directive comme true. 

Ici, si vous modifiez les variables de portée dans la directive, cela ne sera pas reflété dans la portée parente, mais si vous modifiez la propriété d'une variable de portée, cela est reflété dans la portée parente, car vous avez en fait modifié la variable .

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. Portée isolée: cette option est utilisée lorsque vous souhaitez créer une portée qui n'hérite pas de celle du contrôleur. 

Cela se produit lorsque vous créez des plugins car cela rend la directive générique car elle peut être placée dans n'importe quel code HTML et n'est pas affectée par sa portée parent.

Désormais, si vous ne souhaitez aucune interaction avec la portée parente, vous pouvez simplement spécifier la portée en tant qu'objet vide. comme,

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

Généralement, ce n'est pas le cas, car nous avons besoin d'une certaine interaction avec la portée parente, nous souhaitons donc que certaines valeurs/modifications soient transmises via . Pour cette raison, nous utilisons:

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

@ signifie que les modifications apportées à la portée du contrôleur seront répercutées dans la portée de la directive, mais si vous modifiez la valeur dans la portée de la directive, la variable de portée du contrôleur 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 dans {{}}. 

= est bidirectionnel, donc si vous modifiez la variable dans la portée de la directive, la variable de la portée du contrôleur est également affectée.

& est utilisé pour lier la méthode de la portée du contrôleur afin que nous puissions l'appeler à partir de la directive

L'avantage ici est que le nom de la variable n'a pas besoin d'être identique dans la portée du contrôleur et la portée de la directive. 

Exemple, la portée de la directive comporte une variable "dirVar" qui se synchronise avec la variable "contVar" de la portée du contrôleur. Cela donne beaucoup de puissance et de généralisation à la directive puisqu'un contrôleur peut se synchroniser avec la variable v1, tandis qu'un autre contrôleur utilisant la même directive peut demander à dirVar de se synchroniser avec la variable v2.

Vous trouverez ci-dessous un exemple d'utilisation:

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 differnce pour @ et =):

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

Voici un link vers le blog qui le décrit bien. 

33
Kop4lyf

Nous pouvons simplement utiliser: - 

  1. @ : - pour les valeurs de chaîne pour la liaison de données à sens unique. dans un sens, la liaison de données ne peut être transmise qu'à la directive

  2. = : - pour la valeur d'objet pour la liaison de données bidirectionnelle. dans une liaison de données bidirectionnelle, vous pouvez également modifier la valeur de la portée dans la directive ainsi que dans le langage HTML. 

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

MODIFIER

Dans notre composant définition de version angulaire 1.5 et ci-dessus
il existe quatre types de liaisons différents:

  1. = Liaison de données bidirectionnelle : - si nous changeons la valeur, elle sera automatiquement mise à jour
  2. < liaison à sens unique : - lorsque nous souhaitons simplement lire un paramètre à partir d'une portée parent et ne pas le mettre à jour.

  3. @ c'est pour Paramètres de chaîne

  4. & ceci est pour Callbacks au cas où votre composant aurait besoin de sortir quelque chose dans sa portée parente

20
ojus kulkarni

J'ai créé un petit fichier HTML contenant 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
RobertAKARobin

La méthode = correspond à la liaison 2-way, ce qui vous permet de modifier live dans votre directive. Lorsque quelqu'un modifie cette variable en dehors de la directive, les données modifiées se trouvent dans votre directive, mais @ way n'est pas two-way binding. Cela fonctionne comme Text. Vous vous liez une fois et vous n’aurez que sa valeur.

Pour l'obtenir plus clairement, vous pouvez utiliser cet excellent article:

Directive AngularJS Champ d'application '@' et '='

6

La propriété de portée locale @ est utilisée pour accéder aux valeurs de chaîne définies en dehors de la directive.

= Dans les cas où vous devez créer une liaison bidirectionnelle entre la portée externe et la portée isolée de la directive, vous pouvez utiliser le caractère =.

La propriété & local scope permet au consommateur d'une directive de transmettre une fonction que la directive peut appeler. 

Veuillez vérifier le lien ci-dessous qui vous donne une compréhension claire avec des exemples.Je l’ai trouvé vraiment très utile alors pensé à le partager.

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

3
Raphael

Même lorsque la portée est locale, comme dans votre exemple, vous pouvez accéder à la portée par le biais de la propriété $parent. Supposons que, dans le code ci-dessous, title est défini dans la portée parente. Vous pouvez alors accéder à title en tant que $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 avec des attributs.

Un exemple où j'ai trouvé la notation "&", utilisée "pour transmettre des données de la portée isolée via une expression et à la portée parente", utile (et une liaison de données bidirectionnelle ne pouvait pas être utilisée) se trouvait dans une directive pour restituer une structure de données spéciale à l'intérieur d'un ng-repeat.

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

Une partie du rendu consistait en un bouton de suppression. Dans ce cas, il était utile d’attacher une fonction de suppression à l’extérieur via &. Dans la directive de rendu, cela ressemble à

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

La liaison de données bidirectionnelle i.e. data = "=" ne peut pas être utilisée car la fonction de suppression s’exécuterait à chaque cycle $digest, ce qui n’est pas bon, car l’enregistrement est alors immédiatement supprimé et jamais rendu.

3
user3750988

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
Rishul Matta

la principale différence entre eux est juste 

@ Attribute string binding
= Two-way model binding
& Callback method binding
2
Ashish Kamble

@ lie une propriété de portée local/directive à la valeur évaluée de l'attribut DOM . = lie une propriété de portée local/directive à une propriété de portée parent. & binding permet de passer une méthode dans le champ d'application de votre directive afin qu'elle puisse être appelée dans votre directive.

@ Liaison de chaîne d'attribut = Liaison de modèle à deux voies & Liaison de méthode à Callback

0
Ashish Kamble

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

Lorsque vous utilisez {{title}}, seule la valeur de la portée parent est transmise à la vue directive et évaluée. Ceci est limité à un sens, ce qui signifie que le changement ne sera pas reflété dans la portée parent. Vous pouvez également utiliser '=' lorsque vous souhaitez refléter les modifications apportées dans la directive enfant à la portée parent. C'est à double sens.

Puis-je aussi accéder directement au champ parent, sans décorer mon élément avec un attribut?

Lorsque la directive a un attribut scope (scope: {}), vous ne pourrez plus accéder directement à la portée parent. Mais il est toujours possible d'y accéder via scope. $ Parent etc. Si vous supprimez scope de la directive, vous pouvez y accéder directement.

La documentation indique "Il est souvent souhaitable de transmettre des données de la portée isolée Via une expression et à la portée parente", mais cela semble bien fonctionner avec la liaison bidirectionnelle aussi. Pourquoi le voie d'expression être mieux?

Cela dépend du contexte. Si vous souhaitez appeler une expression ou une fonction avec des données, vous utilisez & et si vous souhaitez partager des données, vous pouvez utiliser une méthode bidirectionnelle en utilisant '='

Vous pouvez trouver les différences entre plusieurs façons de transmettre des données à une directive en cliquant sur le lien ci-dessous:

AngularJS - Scopes isolés - @ vs = vs &

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

0
Prashanth

@ Liaison de chaîne d'attribut (un sens) = Liaison de modèle à deux voies & Méthode de rappel

0
Jatin Patel