example - ng-app angularjs




Quelle est la différence entre '@' et '=' dans la portée de la directive dans AngularJS? (10)

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

@ lie une propriété d'étendue 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 sera définie par la propriété de portée parent "title". Comme 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é d'étendue locale / directive à une propriété d'étendue parent . Donc, avec = , vous utilisez le nom de la propriété parent / modèle de portée 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é, alors la chaîne "et les autres" est concaténée avec. La chaîne concaténée finale est ce que la propriété d'étendue locale / directive 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 de 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 que de asynchronously . Vous n'avez pas besoin d'utiliser $ observe () si vous utilisez uniquement la valeur dans 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 parent sans décorer mon élément avec un attribut?

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

scope: { ... }

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

La documentation dit «Souvent, il est souhaitable de transmettre des données de la portée isolée via une expression et à la portée parent», mais cela semble 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. La "liaison d'expression" permet à la directive d'appeler une expression (ou une fonction) définie par un attribut DOM - et vous pouvez également transmettre des données en tant qu'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 la portée parent - vous pouvez utiliser la syntaxe & .

Voir également

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

Et voici quelques extraits pertinents:

  • Du HTML:

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
    
  • De la directive du 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 parent sans décorer mon élément avec un attribut?
  • La documentation dit «Souvent, il est souhaitable de transmettre des données de la portée isolée via une expression et à la portée parent» , mais cela semble 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/


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

Lorsque vous utilisez {{title}}, seule la valeur de périmètre parent sera transmise à la vue directive et évaluée. Ceci est limité à un sens, ce qui signifie que les changements ne seront pas reflétés dans la portée des parents. Vous pouvez utiliser '=' lorsque vous souhaitez également refléter les modifications effectuées dans la directive enfant vers la portée parent. C'est deux façons.

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

Lorsque la directive possède 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. Si vous supprimez scope de directive, vous pouvez y accéder directement.

La documentation dit «Souvent, il est souhaitable de transmettre des données de la portée isolée via une expression et à la portée parent», mais cela semble fonctionner correctement avec la liaison bidirectionnelle. Pourquoi la voie d'expression serait-elle meilleure?

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 la méthode binaire en utilisant '='

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

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

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


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

Les 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 transmettre des chaînes. Ces chaînes prennent en charge les {{}} expressions pour les valeurs interpolées. Par exemple: . L'expression interpolée est évaluée par rapport à la portée parent de la directive.

  2. = la liaison est pour la liaison du modèle bidirectionnel. Le modèle dans le périmètre parent est lié au modèle dans la portée isolée de la directive. Les modifications apportées à un modèle affectent l'autre et vice versa.

  3. & liaison est pour passer une méthode dans la portée de votre directive afin qu'elle puisse être appelée dans votre directive. La méthode est pré-liée à la portée parent de la directive et prend en charge les arguments. Par exemple si la méthode est hello (nom) dans la portée parent, alors pour exécuter la méthode depuis l'intérieur de votre directive, vous devez appeler $ scope.hello ({name: 'world'})

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

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

Les symboles clarifient également la signification de la variable scope dans l'implémentation de votre directive:

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

Par ordre d'utilité (pour moi de toute façon):

  1. =
  2. @
  3. &

Il y a trois façons d'ajouter de la portée dans la directive:

  1. Parent scope : C'est l'héritage de portée par défaut.

La directive et son parent (contrôleur / directive à l'intérieur duquel elle repose) sont identiques. Ainsi, toutes les modifications apportées aux variables d'étendue à l'intérieur de la directive sont également répercutées dans le contrôleur parent. Vous n'avez pas besoin de le spécifier 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 scope de la directive comme true.

Ici, si vous modifiez les variables de portée à l'intérieur de la directive, elles ne refléteront pas 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 parent, puisque vous avez modifié la variable de portée 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. Portée isolée : elle est utilisée lorsque vous souhaitez créer la portée qui n'hérite pas de la portée 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 HTML et n'est pas affectée par sa portée parent.

Maintenant, si vous ne voulez pas d'interaction avec la portée parent, 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

Dans la plupart des cas, ce n'est pas le cas car nous avons besoin d'une interaction avec la portée parentale, nous voulons donc que certaines des valeurs / changements passent. 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 changements de la portée du contrôleur seront reflétés 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.

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

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

& est utilisé pour lier la méthode de portée du contrôleur de sorte que si nécessaire, nous pouvons l'appeler à partir de la directive

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

Exemple, la portée de la directive a 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 car 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.

Voici l'exemple de l'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 différence 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.


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


La méthode = est une liaison bidirectionnelle , ce qui vous permet d'avoir des changements en direct dans votre directive. Quand quelqu'un change cette variable hors de la directive, vous aurez cette donnée modifiée dans votre directive, mais @ way n'est pas une liaison bidirectionnelle. Cela fonctionne comme du texte . Vous liez une fois, et vous n'aurez que sa valeur.

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

Champ d'application de la directive AngularJS '@' et '='


Même lorsque la portée est locale, comme dans votre exemple, vous pouvez accéder à la portée parent via la propriété $parent . Supposons que dans le code ci-dessous, ce title soit défini sur la portée parente. Vous pouvez ensuite accéder au titre 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 en utilisant des attributs.

Un exemple d'où j'ai trouvé la notation "&", qui est utilisé pour "passer des données de la portée isolée via une expression et à la portée parent", utile (et une liaison de données bidirectionnelle n'a pas pu être utilisée) était dans une directive pour rendre une structure de données spéciale à 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 de suppression et ici il était utile d'attacher une fonction de suppression de la portée extérieure via &. A l'intérieur de la directive render, il semble que

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

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


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

@ get comme chaîne

  • Cela ne crée aucune liaison. Vous obtenez simplement le mot que vous avez passé comme une chaîne

= Liaison à 2 voies

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

& Cela se comporte un peu différemment, car la portée obtient une fonction qui renvoie l'objet qui a été transmis . Je suppose que c'était nécessaire pour que ça marche. Le violon devrait le rendre clair.

  • Après avoir appelé cette fonction getter, l'objet résultant se comporte comme suit:
    • si une fonction a été transmise: alors la fonction est exécutée dans la fermeture parent (contrôleur) lorsqu'elle est appelée
    • si un non-fonction a été transmis: il suffit d'obtenir une copie locale de l'objet qui n'a pas de liaison


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


@ et = voir d'autres réponses.

Un gotcha sur &
TL; DR;
& obtient une expression (non seulement fonctionne comme dans les exemples 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 la capacité de remplacer n'importe quelle variable (nom de fonction pair) d'expression, en passant un objet avec les variables.

expliqué
& est une référence d'expression, cela signifie que si vous passez quelque chose comme <myDirective expr="x==y"></myDirective>
dans la directive, cette expression sera une fonction, qui appelle l'expression, comme:
function expr(){return x == y} .
Donc, dans le html de la directive <button ng-click="expr()"></button> appellera l'expression. Dans js de la directive, $scope.expr() appellera aussi l'expression.
L'expression sera appelée avec $ scope.x et $ scope.y du parent.
Vous avez la possibilité de remplacer les paramètres!
Si vous les définissez par appel, par exemple <button ng-click="expr({x:5})"></button>
alors l'expression sera appelée avec le paramètre x et le paramètre y du parent.
Vous pouvez remplacer les deux.
Maintenant vous savez, pourquoi <button ng-click="functionFromParent({x:5})"></button> fonctionne.
Parce qu'il appelle simplement l'expression du 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 de l'enfant:
<button ng-click="functionFromParent({x:5, z: 4})"></button> .
ou même avec remplacement de fonction:
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button> .

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

Exemples:
modèle de directive vs code appelé:
parent a défini $ scope.x, $ scope.y:
modèle parent: <myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button> appelle $scope.x==$scope.y
<button ng-click="expr({x: 5})"></button> appelle 5 == $scope.y
<button ng-click="expr({x:5, y:6})"></button> appelle 5 == 6

parent a défini $ scope.function1, $ scope.x, $ scope.y:
modèle parent: <myDirective expr="function1(x) + y"></myDirective>

<button ng-click="expr()"></button> appelle $scope.function1($scope.x) + $scope.y
<button ng-click="expr({x: 5})"></button> appelle $scope.function1(5) + $scope.y
<button ng-click="expr({x:5, y:6})"></button> appelle $scope.function1(5) + 6
La directive a $ scope.myFn comme fonction:
<button ng-click="expr({function1: myFn, x:5, y:6})"></button> appelle $scope.myFn(5) + 6





isolated-scope