11

私は少しフィドルを準備し、それを最小限に煮詰めました:

http://jsfiddle.net/lpeterse/NdhjD/4/

<script type="text/javascript">
    angular.module('app', ['ui.bootstrap']);

    function Ctrl($scope) {
      $scope.foo = "42";
}
</script>


<div ng-app="app" ng-controller="Ctrl">
    1: {{foo}}<br />
    2: <input ng-model="foo" />
    <tabs>
        <pane heading="tab">
            3: {{foo}}<br />
            4: <input ng-model="foo" />
        </pane>
    </tabs>    
</div>

最初は、すべてのビューがモデルを参照しますCtrl.foo

入力で何かを変更する2:と、モデルが適切に更新され、この変更がすべてのビューに反映されます。

入力の何かを変更4:しても、同じペインに含まれるビューにのみ影響します。どういうわけか分岐したスコープのように動作します。その後の変更2:はタブに反映されなくなりました。

ディレクティブ、スコープ、トランスクルージョンに関する角度のあるドキュメントを読みましたが、この望ましくない動作の説明が見つかりませんでした。

ヒントをいただければ幸いです:-)

4

3 に答える 3

12

問題は、プリミティブを編集するときの ng-repeat と同じです。<pane>ディレクティブは、親から継承する新しいスコープを作成します。

ここで、Javascript の継承が機能する方法を考えると、<pane>ディレクティブには文字列プリミティブの独自のコピーがあり、fooそれを編集するときはペインの子スコープでのみ編集します。

簡単な解決策はfoo、親の Ctrl にオブジェクトを配置することです。

function Ctrl($scope) {
  $scope.data = { foo: 42 };
}

次に、HTML でこれを行うことができます。

<tabs><pane><input ng-model="data.foo"></pane></tabs>

オブジェクトで機能するのはなぜですか?<pane>が親のスコープを継承する場合、その参照dataはメモリ内の親 Ctrl と同じオブジェクトを参照するためです。文字列や数値などのプリミティブは継承でコピーされ、オブジェクトは単に同じオブジェクトへの新しいポインターを作成します。

TL;DR:の新しいスコープは文字列プリミティブを新しいコピーとして<pane>継承し、編集時に親 Ctrl で変更されません。の新しいスコープ、同じオブジェクトへの参照としてオブジェクトを継承し、スコープで編集すると、同じオブジェクトが親スコープで参照されます。foofoo<pane>data<pane>

役立つ記事: https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance

于 2013-02-19T16:18:07.177 に答える
4

およびディレクティブはそれぞれ、親スコープから原型的に継承する新しいトランスクルードされた子スコープを作成します (どちらも を持っているため<tabs>) 、および親スコープから原型的に継承しない分離子スコープを作成します。内部は、transcluded 子スコープを使用します。<pane>transclude: true,<input...><pane>

input内部<pane>が最初にレンダリングされると、 の値が取り込まれます$scope.foo。ここで、通常の JavaScript プロトタイプ継承が機能します... 最初fooは、トランスクルージョンされた子スコープで定義されていないため (プロトタイプ継承はプリミティブをコピーしません)、JavaScript はプロトタイプ チェーンに従い、親オブジェクト/$scope を調べて、そこで見つけます。 42テキストボックスに入れられます。トランスクルードされた子スコープは、影響を受けたり変更されたりしていません (まだ)。

最初のテキスト ボックスを編集すると、2 番目のテキスト ボックスが更新されます。これは、JavaScript がまだプロトタイプの継承を使用して の値を見つけているためです$scope.foo

2 番目のテキスト ボックスを編集すると429、Angular は値を$scope.fooに書き込みますが、$scope はトランスクルードされた子スコープであることに注意してください。はプリミティブであるためfoo、その子スコープに新しいプロパティを作成します。これが、良くも悪くも JavaScript のしくみです。この新しいプロパティは、同じ名前の親スコープ プロパティを隠します。ここでは、プロトタイプの継承は機能しません。(Andy が彼の投稿で言及している記事 ( SO にもあります) も、これを写真付きで詳細に説明しています。) トランスクルードされた子スコープにはfooプロパティがあるため、そのローカル プロパティを読み取りと書き込みに使用するようになります。親スコープから「切断」されました。

(プリミティブではなく) オブジェクトを使用すると、プロトタイプの継承が常に機能するため、問題が解決します。トランスクルードされた子スコープは、親スコープ内のオブジェクトへの参照を取得します。トランスクルードされた子スコープではなく、親のオブジェクトに書き込みdata.fooます。data

于 2013-02-28T17:27:28.570 に答える
0

問題は tabs ディレクティブにあります。ui-bootstrap-tpls-0.1.0.js の 1044 行目だと思います。

それに変更scope: {}するscope: { foo: '='}と、双方向のデータバインディングが得られます。

Angular Docsから:

= または =attr - attr 属性の値を介して定義された name のローカル スコープ プロパティと親スコープ プロパティとの間の双方向バインディングを設定します。属性名が指定されていない場合、属性名はローカル名と同じであると見なされます。スコープのウィジェット定義: { localModel:'=myAttr' } を指定すると、ウィジェット スコープ プロパティ localModel は、親スコープの parentModel の値を反映します。parentModel への変更は localModel に反映され、localModel の変更は parentModel に反映されます。

于 2013-02-19T16:10:43.223 に答える