web-dev-qa-db-ja.com

Angularjsが混乱し、スコープとバインディングをトランスクルードおよび分離する

スコープが制限されているディレクティブに関して、モデルのスコープとそのバインディングを理解するのに苦労しています。

ディレクティブのスコープを制限するということは、controller。$ scopeとdirective.scopeが同じものではなくなったことを意味します。ただし、ディレクティブテンプレート内またはhtml内のモデルの配置がデータバインディングにどのように影響するかについて混乱しています。私は非常に基本的なものを見逃していると感じています。先に進むには、これを理解する必要があります。

次のコードを使用します(ここを中心に: http://jsfiddle.net/2ams6/

JavaScript

var app = angular.module('app',[]);
app.controller('Ctrl',function($scope){
});
app.directive('testel', function(){
    return {
        restrict: 'E',
        scope: {
            title: '@'
        },
        transclude: true,
        template:   '<div ng-transclude>'+
                    '<h3>Template title: {{title}}</h3>' +
                    '<h3>Template data.title:{{data.title}}</h3>' +
                    '</div>'
    }    
}); 

HTML

<div ng-app='app'>
    <div ng-controller="Ctrl">
        <input ng-model="data.title">
        <testel title="{{data.title}}">
            <h3>Transclude title:{{title}}</span></h3>
            <h3>Transclude data.title:{{data.title}}</h3>
        </testel>
    </div>
</div>

モデルは、テンプレート内の{{title}}、およびトランスクルージョンの{{data.title}}のみを更新します。 トランスクルージョンの{{title}}やテンプレートの{{data.title}}ではないのはなぜですか?

そのように入力をトランスクルージョン内に移動します(ここを中心に: http://jsfiddle.net/eV8q8/1/ ):

<div ng-controller="Ctrl">
    <testel title="{{data.title}}">
        <input ng-model="data.title">
         <h3>Transclude title: <span style="color:red">{{title}}</span></h3>

         <h3>Transclude data.title: <span style="color:red">{{data.title}}</span></h3>

    </testel>
</div>

現在は、トランスクルード{{data:title}}のみが更新されることを意味します。 テンプレート{{title}}または{{data.title}}のどちらでもない、または{{title}}?をトランスクルードしない理由

そして最後に、そのように入力をテンプレート内に移動します(ここを中心に: http://jsfiddle.net/4ngmf/2/ ):

template: '<div ng-transclude>' +
            '<input ng-model="data.title" />' +
            '<h3>Template title: {{title}}</h3>' +
            '<h3>Template data.title: {{data.title}}</h3>' +
            '</div>'

現在は、テンプレート{{data.title}}のみが更新されることを意味します。 もう一度、他の3つのバインディングはどうですか?

私は顔に私を見つめる明らかな何かがあり、私はそれを見逃していると思います。これを手に入れてくれたら、ビールを買うか、ポイントをあげるか、そういうものをあげる。どうもありがとう。

55
dewd

フィドルは3つのスコープを作成します。

  1. ng-controllerのため、コントローラーCtrlに関連付けられたスコープ
  2. transclude: trueが原因でディレクティブがトランスクルードされたスコープ
  3. scope: { ... }のため、ディレクティブはスコープを分離します

Fiddle1では、テキストボックスに何かを入力する前に、次のものがあります。

enter image description here

スコープ003は、コントローラーに関連付けられたスコープです。テキストボックスにはまだ入力しなかったため、dataプロパティはありません。分離スコープ004では、titleプロパティが作成されましたが、空です。親スコープにはdata.titleプロパティがまだないため、空です。

テキストボックスにmy titleと入力すると、次のようになります。

enter image description here

コントローラースコープ003には新しいdataオブジェクトプロパティがあり(これが黄色で表示されている理由です)、titleプロパティがmy titleに設定されています。分離スコーププロパティtitledata.titleの内挿値に一方向データバインドされるため、値my titleも取得します(値は変更されたため黄色になります)。

トランスクルードされたスコープは、プロトタイプでコントローラースコープを継承するため、トランスクルードされたHTML内でangularはプロトタイプチェーンをたどり、親スコープで$scope.data.titleを見つけることができます(ただし$scope.titleはそこに存在しない)。

分離スコープは、独自のプロパティにのみアクセスできるため、プロパティtitleのみにアクセスできます。

入力する前のfiddle2には、fiddle1と同じ画像があります。

my titleと入力した後:

enter image description here

新しいdata.titleプロパティが表示された場所に注意してください-トランスクルードされたスコープ上。分離スコープはまだコントローラースコープでdata.titleを探していますが、今回はそこにないので、そのtitleプロパティ値は空のままです。

Fiddle3では、入力する前にfiddle1と同じ画像が表示されます。

my titleと入力した後:

enter image description here

分離スコープの新しいdata.titleプロパティが表示されていることに注目してください。他のスコープはどれも分離スコープにアクセスできないため、文字列my titleは他のどこにも表示されません。


Angular v1.2:の更新

変更により eed299a Angularは、トランスクルージョンする前にトランスクルージョンポイントをクリアするため、変更しない限り、Template title: ...およびTemplate data.title: ...パーツは表示されません。次のようなng-transcludeのみのテンプレート

'<h3>Template title: <span style="color:red">{{title}}</span></h3>' +
'<h3>Template data.title: <span style="color:red">{{data.title}}</span></h3>' +
'<div ng-transclude></div>'

以下のAngular v1.3の更新では、このテンプレートが変更されました。


Angular v1.3 +:の更新

Angular v1.3であるため、トランスクルードされたスコープは、コントローラースコープの子ではなく、ディレクティブの分離スコープの子になります。したがって、fiddle1で何かを入力する前に:

enter image description here

このアップデートの画像は Peri $ scope ツールで描画されるため、画像は少し異なります。 @は、@構文を使用する分離スコーププロパティがあることを示し、ピンクの背景は、ツールがマッピングの祖先参照を見つけることができなかったことを意味します(これは、 tはまだテキストボックスに入力します)。

テキストボックスにmy titleと入力すると、次のようになります。

enter image description here

@バインディングを使用する分離プロパティは、@シンボルの後に分離スコープで補間された文字列の結果を常に表示します。また、Peri $ scopeは祖先スコープでこの正確な文字列値を見つけることができたため、そのプロパティへの参照も表示されます。

Fiddle 2では、入力する前に、fiddle1と同じ画像が表示されます。

my titleと入力した後:

enter image description here

新しいdata.titleプロパティが表示された場所に注目してください-トランスクルードされたスコープ上。分離スコープはまだコントローラースコープでdata.titleを探していますが、今回はそこにないため、そのtitleプロパティ値は空のままです。

Fiddle3では、入力する前にfiddle1と同じ画像が表示されます。

my titleと入力した後:

enter image description here

分離スコープの新しいdata.titleプロパティが表示された場所に注目してください。トランスクルードされたスコープは、$parent関係を介して分離スコープにアクセスできますが、titleまたはdata.titleを検索することはありません。コントローラースコープのみを検索します(つまり、プロトタイプの継承に従います)、コントローラースコープにはこれらのプロパティが定義されていません。

113
Mark Rajcok

マークの素晴らしい回路図を含む提示されたすべての答えを読んだ後、これは私のスコープの理解であり、私の質問ごとの継承です。適切に更新できるように、この図がどこに落ちるかについてのコメントをいただければ幸いです。マークが提示したものとは異なる見方を提供することを願っています。

Scope inheritance

22
dewd

よく尋ねました、ところで!私の答えが雄弁であることを願っています。

答えは、トランスクルードされた要素がどのようにスコープを取得するかに関係しています。

要約すると、2つのスコープがあります。

  1. $scope.data.titleを持つコントローラーのスコープ。 (input要素によって暗黙的に追加されます)
  2. $scope.titleを持つディレクティブのスコープ。

コントローラの$scope.data.titleを変更すると、ディレクティブの$scope.titleも変更されます。

HTMLの2つのセクション、トランスクルードされたテンプレートとテンプレートもあります。何が起こっているかというと、トランスクルードされたHTMLはcontroller'sスコープにあり、テンプレートHTMLはdirective'sスコープ。したがって、トランスクルードされたHTMLはtitleについて何も知りません。また、テンプレートスコープはdata.titleについて何も知りません。

これは実際、トランスクルージョンが意図したとおりです-ディレクティブの子要素が親スコープ、この場合はコントローラーのスコープを保持できるようにするため設計上、トランスクルードされた要素はディレクティブ内にあることを認識しないため、ディレクティブのスコープにアクセスできません。

一方、ディレクティブテンプレートは、ディレクティブのスコープにのみアクセスできます。

名前をもう少し明確にするためにコードを少し変更しました(同じ機能ですが)

http://jsfiddle.net/yWWVs/2/

8
Roy Truelove