web-dev-qa-db-ja.com

AngularJSのディレクティブスコープにおける '@'と '='の違いは何ですか?

私はトピックに関するAngularJSのドキュメントを注意深く読み、それからディレクティブをいじっていました。これが フィドル です。

そして、ここにいくつかの関連スニペットがあります:

  • HTMLから:

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
    
  • Paneディレクティブから:

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

得られないことがいくつかあります。

  • なぜ"{{title}}"'@'を、そして"title"'='を一緒に使わなければならないのですか?
  • 要素を属性で装飾することなく、親スコープに直接アクセスすることもできますか?
  • "孤立したスコープから親のスコープへデータを渡すことが望ましいことが多いです" しかし双方向バインディングでもうまくいくようです。発現経路が良いのはなぜでしょうか。

私は式の解法も示す別のフィドルを見つけました: http://jsfiddle.net/maxisam/QrCXh/

1040
iwein

「{{title}}」を「@」で、「title」を「=」で使用する必要があるのはなぜですか?

@は、ローカル/ディレクティブスコーププロパティをDOM属性の評価値にバインドします。 title=title1またはtitle="title1"を使用する場合、DOM属性「title」の値は単に文字列title1です。 title="{{title}}"を使用する場合、DOM属性 "title"の値は{{title}}の補間値であるため、文字列は親スコーププロパティ "title"が現在設定されているものになります。属性値は常に文字列であるため、@を使用すると、ディレクティブのスコープ内のこのプロパティの文字列値になります。

=は、ローカル/ディレクティブスコーププロパティを親スコーププロパティにバインドします。 =では、親モデル/スコーププロパティ名をDOM属性の値として使用します。 {{}}sを=とともに使用することはできません。

@を使用すると、title="{{title}} and then some"のようなことができます-{{title}}が補間され、「and them some」という文字列がそれに連結されます。最終的な連結文字列は、ローカル/ディレクティブスコーププロパティが取得するものです。 (これは=ではできません。@のみです。)

@では、リンク関数で値を使用する必要がある場合は、attr.$observe('title', function(value) { ... })を使用する必要があります。たとえば、if(scope.title == "...")は期待どおりには機能しません。これは、この属性にのみアクセスできることを意味することに注意してください asynchronously 。テンプレートの値のみを使用している場合は、$ observe()を使用する必要はありません。例:template: '<div>{{title}}</div>'

=を使用すると、$ observeを使用する必要はありません。

要素を属性で装飾せずに、親スコープに直接アクセスすることもできますか?

はい。ただし、分離スコープを使用しない場合のみ。ディレクティブからこの行を削除します

scope: { ... }

そして、ディレクティブは新しいスコープを作成しません。親スコープを使用します。その後、すべての親スコーププロパティに直接アクセスできます。

ドキュメントには、「式を介して分離スコープから親スコープにデータを渡すことが望ましい場合が多い」とありますが、双方向バインディングでもうまくいくようです。なぜ表現ルートがより良いのでしょうか?

はい。双方向バインディングでは、ローカル/ディレクティブスコープと親スコープがデータを共有できます。 「式バインディング」により、ディレクティブはDOM属性で定義された式(または関数)を呼び出すことができます。また、データを引数として式または関数に渡すこともできます。したがって、親とデータを共有する必要がない場合-親スコープで定義された関数を呼び出すだけ-場合は、構文を使用できます。

こちらもご覧ください

1139
Mark Rajcok

ここにはたくさんの素晴らしい答えがありますが、@=、および&バインディングの違いについての私の見解を私に提供したいと思います。

3つのバインディングはすべて、要素の属性を介して、親スコープからディレクティブの分離スコープにデータを渡す方法です。

  1. @ bindingは文字列を渡すためのものです。 これらの文字列は、内挿値の{{}}式をサポートしています。 例えば: 。内挿された式はディレクティブの親スコープに対して評価されます。

  2. = bindingは、双方向モデルのバインディング用です。親スコープ内のモデルは、指令の分離スコープ内のモデルにリンクされています。 1つのモデルへの変更は他のモデルに影響を及ぼし、その逆も同様です。

  3. bindingは、メソッドをあなたのディレクティブのスコープに渡して、そのメソッドをあなたのディレクティブ内で呼び出せるようにするためのものです。メソッドはディレクティブの親スコープに束縛され、引数をサポートします。例えば、メソッドが親スコープ内でhello(name)である場合、であなたのディレクティブの中からメソッドを実行するためには、を呼び出す必要があります)

簡単な説明でスコープのバインディングを参照することで、これらの違いを覚えやすくなります。

  • @ 属性文字列バインディング
  • = 双方向モデルバインディング
  • & コールバックメソッドバインディング

また、シンボルによって、スコープ変数がディレクティブの実装内で何を表しているかが明確になります。

  • @ 文字列
  • = モデル
  • & method

便利さのために(とにかく)

  1. =
  2. @
531
pixelbits

=は双方向バインディングを意味するので、親スコープへの変数への参照です。つまり、ディレクティブ内で変数を変更すると、それは親スコープ内でも変更されます。

@は、変数がディレクティブにコピー(クローン)されることを意味します。

私の知る限りでは、<pane bi-title="{{title}}" title="{{title}}">{{text}}</pane>も機能するはずです。 bi-titleは、親のスコープ変数の値を受け取りますが、これはディレクティブで変更できます。

親スコープ内のいくつかの変数を変更する必要がある場合は、ディレクティブ内から親スコープで関数を実行することができます(またはサービスを介してデータを渡すことができます)。

62
asgoth

これが実際の例でどのように機能するかをもっと知りたいのならば。 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

@ 文字列として取得

  • これはいかなるバインディングも作成しません。渡したWordを文字列として取得しているだけです。

= 双方向バインディング

  • コントローラから行われた変更は、ディレクティブによって保持されている参照に反映されます。

&これは少々異なった振る舞いをします、なぜならスコープはで渡されたオブジェクトを返す関数を取得するからです。これを機能させるにはこれが必要だと思います。 フィドルはこれを明確にする必要があります。

  • このgetter関数を呼び出した後、結果のオブジェクトは次のように動作します。
    • functionが渡された場合:この関数は呼び出されたときに親(コントローラ)クロージャで実行されます。
    • non-functionが渡された場合:単にバインディングを持たないオブジェクトのローカルコピーを取得します。


このフィドルは、それらがどのように機能するのかを示すべきです 。うまくいけば私がget...について何を意味するのか理解するために名前に&が付いているスコープ関数に特に注意を払う

36
geg

ディレクティブにスコープを追加する方法は3つあります。

  1. 親スコープ :これはデフォルトのスコープ継承です。 

ディレクティブとその親(それが含まれるコントローラー/ディレクティブ)の有効範囲は同じです。したがって、directiveの中の有効範囲変数に加えられた変更は、親コントローラーにも反映されます。これがデフォルトなので指定する必要はありません。

  1. 子スコープ :ディレクティブは、ディレクティブのスコープ変数をtrueに指定した場合、親スコープから継承する子スコープを作成します。 

ここで、ディレクティブ内でスコープ変数を変更しても、親スコープには反映されませんが、スコープ変数のプロパティを変更すると、実際には親のスコープ変数を変更したので、親スコープに反映されます。 。

例、

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. 分離スコープ :これは、コントローラスコープから継承しないスコープを作成したい場合に使用します。 

これは、プラグインを作成しているときに発生します。これは、どのHTMLにも配置でき、その親スコープの影響を受けないため、ディレクティブが一般的になるためです。

親スコープとのやり取りが不要な場合は、単にスコープを空のオブジェクトとして指定できます。好きです、

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

親のスコープとのやり取りが必要なので、ほとんどの場合これは当てはまりません。そのため、いくつかの値/変更を渡す必要があります。このため、以下を使用します。

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

@ は、コントローラスコープからの変更がディレクティブスコープに反映されることを意味しますが、ディレクティブスコープ内の値を変更しても、コントローラスコープ変数は影響を受けません。 

@は常にマップされた属性が式であることを期待します。これはとても重要です; 「@」プレフィックスを機能させるには、属性値を{{}}で囲む必要があるためです。 

= は双方向であるため、ディレクティブスコープ内の変数を変更すると、コントローラスコープ変数も影響を受けます。

はコントローラのスコープメソッドをバインドするために使用されるので、必要に応じてディレクティブから呼び出すことができます。

ここでの利点は、変数の名前がコントローラスコープとディレクティブスコープで同じである必要がないことです。 

たとえば、ディレクティブスコープには、コントローラスコープの変数「contVar」と同期する変数「dirVar」があります。 1つのコントローラが変数v1と同期できる一方、同じディレクティブを使用している別のコントローラがdirVarに変数v2と同期するように依頼できるので、これは指令に多くの力と一般化を与えます。

下記は使用例です。

ディレクティブとコントローラは次のとおりです。

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

そしてhtml(@と=の違いに注意してください):

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

これは link に書いてあります。 

33
Kop4lyf

単に使用することができます: -

  1. @: - 一方向のString値の場合データバインディング。一方向のデータバインディングでは、スコープ値をディレクティブにのみ渡すことができます

  2. =: - 双方向データバインディングのオブジェクト値。双方向のデータバインディングでは、ディレクティブおよびHTMLでもスコープ値を変更できます。 

  3. : - メソッドと関数用。

編集

Angular version 1.5Componentの定義で_以上
4種類のバインディングがあります。

  1. =双方向データバインディング: - 値を変更すると自動的に更新されます
  2. <一方向バインディング: - 親スコープからパラメータを読み込み、それを更新したくない場合。

  3. @これはString Parametersのためのものです

  4. &これはあなたのコンポーネントがその親スコープに何かを出力する必要がある場合のためのCallbacksのためのものです

20
ojus kulkarni

私はAngularコードを含む小さなHTMLファイルを作成しました。

<!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

= wayは 双方向バインディング です。これにより、ディレクティブ内で live の変更を行うことができます。誰かがその変数をディレクティブ外で変更すると、その変更されたデータはディレクティブ内にありますが、 @ wayは 双方向バインディングではありません Text のように動作します。あなたは一度だけバインドすれば、その価値しか得られないでしょう。

より明確にするために、この素​​晴らしい記事を使うことができます。

AngularJSディレクティブスコープ '@'と '='

6

@ local scopeプロパティは、ディレクティブの外側で定義されている文字列値にアクセスするために使用されます。

= 外側のスコープとディレクティブの分離スコープの間に双方向のバインディングを作成する必要がある場合は、=文字を使用できます。

local scopeプロパティにより、ディレクティブの利用者は、そのディレクティブが呼び出すことができる関数を渡すことができます。 

例を使って明確に理解できるように、以下のリンクを確認してください。本当に役に立つので、共有することを考えました。

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

3
Raphael

例のようにスコープがローカルであっても、プロパティ$parentを通して親スコープにアクセスできます。以下のコードでは、titleが親スコープで定義されていると仮定します。あなたは$parent.titleとしてタイトルにアクセスすることができます:

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

ただし、ほとんどの場合、属性を使用して同じ効果が得られます。

「式を介して分離スコープからデータを親スコープに渡すために使用される」(および双方向のデータバインディングを使用できない)表記法が使用されている例がディレクティブにあります。 ng-repeatの中に特別なデータ構造を描画するためのものです。

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

レンダリングの一部は削除ボタンであり、ここで&を介して外側のスコープから削除関数を追加すると便利でした。 render-directiveの中では、

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

双方向のデータバインディング、つまりdata = "="は、$digestサイクルごとに実行されるため使用できません。レコードがすぐに削除されてレンダリングされることがないため、これは不適切です。

3
user3750988

私はすべての可能なオプションをいじるのに実装しました。

それはすべてのオプションを扱います:

scope:{
    name:'&'
},

scope:{
    name:'='
},

scope:{
    name:'@'
},

scope:{

},

scope:true,

https://jsfiddle.net/rishulmatta/v7xf2ujm

3
Rishul Matta

それらの主な違いはただ 

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

@=は他の答えを見てください。 

&についての1つのgotcha
TL; DR;
&は、親からexpression(他の答えの例のような関数だけでなく)を取得し、それをディレクティブ内の関数として設定し、それが式を呼び出します。そしてこの関数は、変数を持つオブジェクトを渡すことによって、式の任意の変数を置換(関数名でさえ)する能力を持ちます。 

説明
&は式の参照です。つまり、 <myDirective expr="x==y"></myDirective>のように渡すとします。
ディレクティブでは、このexprは、次のように式を呼び出す関数です。
function expr(){return x == y}
そのため、ディレクティブのhtml <button ng-click="expr()"></button>では式を呼び出します。ディレクティブのjsでは、$scope.expr()だけが式も呼び出します。
式は親の$ scope.xと$ scope.yで呼び出されます。
あなたはパラメータを上書きすることができます!
電話で設定した場合は、 <button ng-click="expr({x:5})"></button>
その後、式はあなたのパラメータxと親のパラメータyで呼び出されます。
両方を上書きすることができます。
これで、<button ng-click="functionFromParent({x:5})"></button>が機能する理由がわかりました。
これは単にparentの式(例えば<myDirective functionFromParent="function1(x)"></myDirective>)を呼び出すだけで、可能な値をあなたの指定したパラメータ、この場合はxに置き換えます。
かもしれない:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
または
<myDirective functionFromParent="function1(x) + z"></myDirective>
チャイルドコール付き:
<button ng-click="functionFromParent({x:5, z: 4})"></button>
または機能を置き換えた場合でも
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>

それは単なる式であり、それが関数なのか、それとも多くの関数なのか、あるいは単に比較なのかは関係ありません。そして、この式のany変数を置き換えることができます。

例:
ディレクティブテンプレートと呼ばれるコード:
親は$ scope.x、$ scope.yを定義しました:
親テンプレート:<myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button>$scope.x==$scope.yを呼び出します
<button ng-click="expr({x: 5})"></button>5 == $scope.yを呼び出します
<button ng-click="expr({x:5, y:6})"></button>5 == 6を呼び出します 

親が$ scope.function1、$ scope.x、$ scope.yを定義しました。
親テンプレート:<myDirective expr="function1(x) + y"></myDirective> 

<button ng-click="expr()"></button>$scope.function1($scope.x) + $scope.yを呼び出します
<button ng-click="expr({x: 5})"></button>$scope.function1(5) + $scope.yを呼び出します
<button ng-click="expr({x:5, y:6})"></button>$scope.function1(5) + 6を呼び出します
ディレクティブは関数として$ scope.myFnを持っています:
<button ng-click="expr({function1: myFn, x:5, y:6})"></button>$scope.myFn(5) + 6を呼び出します 

1
ya_dimon

@は、ローカル/ディレクティブスコーププロパティを評価されたDOM属性の値にバインドします。 &bindingは、メソッドをディレクティブのスコープ内に渡して、そのメソッドがディレクティブ内で呼び出されるようにするためのものです。

@属性文字列バインディング =双方向モデルバインディング&コールバックメソッドバインディング

0
Ashish Kamble

なぜ「{{title}}」を「@」、「title」を「=」と一緒に使用する必要があるのですか。

{{title}}を使用すると、親スコープの値だけがディレクティブビューに渡されて評価されます。これは一方向に限られています。つまり、変更は親スコープには反映されません。子ディレクティブで行われた変更を親スコープにも反映させたい場合は、 '='を使用できます。これは双方向です。

要素を属性で装飾せずに直接親スコープにアクセスすることもできますか?

ディレクティブにscope属性が含まれている場合(scope:{})、親スコープに直接アクセスすることはできなくなります。しかしそれでもscopeを通してアクセスすることは可能です。$ parent etc.ディレクティブからscopeを削除すれば、直接アクセスすることができます。

ドキュメントには、「分離スコープから親スコープにデータを渡すことが望ましい」と書かれていますが、は双方向バインディングでもうまく機能するようです。なぜ式の方が良いのでしょうか。

状況によって異なります。データで式や関数を呼び出したい場合は&を使用し、データを共有したい場合は '='を使用して双方向の方法を使用できます。

リンクの下にあるディレクティブにデータを渡す方法の違いはいくつかあります。

AngularJS - 独立スコープ - @ vs = vs&

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

0
Prashanth

@属性文字列バインディング(一方向) =双方向モデルバインディング&コールバックメソッドバインディング

0
Jatin Patel