58

モデルにバインドされているコントローラーにテキストボックスがありnameます。コントローラ内にディレクティブがあり、同じモデルにバインドされているディレクティブ内に別のテキストボックスがありますname

<div class="border" ng-controller="editCtrl">
   Controller: editCtrl <br/>
   <input type="text" ng-model="name" />
   <br/>
   <tabs>
      Directive: tabs <br/>
      <input type="text" ng-model="name"/>
   </tabs>
</div>

mod.directive('tabs', function() {
  return {
    restrict: 'E',
    transclude: true, 
    template:
      '<div class="border" ng-transclude></div>',
  };
});

外側のテキストボックスに何かを入力すると、内側のテキストボックスに反映されますが、内側のテキストボックスに何かを入力すると、機能しなくなります。つまり、両方のテキストボックスに同じ値が反映されなくなります。

http://jsfiddle.net/uzairfarooq/MNBLd/の例を参照してください。

また、双方向バインディングattr(scope: {name: '='})を使用してみましたが、構文エラーが発生します。使用しscope: {name: '@'}ても同じ効果があります。

どんな助けでも大歓迎です。

受け入れられた答えに加えて、この記事は私が子供のscpoの典型的な継承を理解するのに本当に役立ちました。スコープに問題がある方は、よくお読みになることを強くお勧めします。

4

3 に答える 3

128

ディレクティブを使用するtransclude: trueと、ディレクティブは新しい(トランスクルージョンされた)子スコープを作成します。この新しいスコープは、通常、親スコープから継承します。あなたの場合、親スコープはeditCtrlコントローラーに関連付けられたスコープです。

子スコープ(つまり、ng-model)で双方向データバインディングを使用して、プリミティブ値(たとえば、name)を保持する親スコーププロパティにバインドすると、常に問題が発生します-まあ、期待どおりに機能しないと言えます。子でスコーププロパティが変更されると(たとえば、2番目のテキストボックスに入力すると)、子は同じ名前の親スコーププロパティを非表示/シャドウにする新しいスコーププロパティを作成します。親プロパティがプリミティブ値を保持している場合、その値は(基本的に)子プロパティの作成時に子プロパティにコピーされます。子スコープの将来の変更(たとえば、2番目のテキストボックス)は、子プロパティにのみ影響します。

2番目のテキストボックスに入力する前(つまり、子でプロパティが変更される前)、子/トランスクルージョンスコープは、nameプロトタイプの継承を介して親スコープでプロパティを検索します(下の図の破線)。これが、2つのテキストボックスが最初に同期したままである理由です。以下では、最初のテキストボックスに「マーク」と入力すると、スコープは次のようになります。

トランスクルージョンされたスコープは継承チェーンに従います

2つのスコープを調べることができるフィドルを作成しました。2番目のテキストボックスに入力する前に、2番目のテキストボックスの横にある[スコープを表示]リンクをクリックします。これにより、トランスクルージョンされた子スコープを確認できます。nameこの時点では、プロパティがないことに気付くでしょう。コンソールをクリアし、2番目のテキストボックスに入力して、リンクをもう一度クリックします。子スコープにnameプロパティがあり、初期値は親プロパティが持っていた値(「マーク」)であることがわかります。2番目のテキストボックスに「likesAngular」と入力すると、スコープは次のようになります。

トランスクルージョンされたプリミティブは親プロパティを非表示にします

2つの解決策があります:

  1. @ pgreen2が提案することを実行します(これは「ベストプラクティス」ソリューションです)-プリミティブの代わりにオブジェクトを使用します。オブジェクトが使用される場合、子/トランスクルージョンされたスコープは新しいプロパティを取得しません。ここでは、プロトタイプの継承のみが機能します。次の図では、editCtrlの$scopeにこのオブジェクトが定義されていると想定しています
    $scope.myObject = { name: "Mark", anotherProp: ... }
    親のオブジェクト
  2. 子スコープで$parentを使用します(これは脆弱なソリューションであり、HTML構造についての仮定を行うため、お勧めしません):ng-model="$parent.name"<tabs>要素内の<input>内で使用します。上の最初の写真は、これがどのように機能するかを示しています。

scope: {name: '='}双方向データバインディングを使用する場合(つまり、'='を使用する場合)、補間は許可されないため、使用時に構文エラーが発生します。つまり、{{}}は使用できません。<tabs name="{{name}}">使用する代わりに<tabs name="name">

'@'の使用は、トランスクルージョンの場合と同じように機能します。これは、ng-transcludeが、を使用して作成された分離スコープではなく、トランスクルージョンスコープを使用するためscope: { ... }です。

スコープ(写真を含む)の(多くの)詳細について
は、AngularJSのスコープのプロトタイプ/プロトタイプの継承のニュアンスは何ですか?を参照してください。

于 2013-01-23T16:46:54.110 に答える
10

問題はスコーピングに関係していると思います。最初は内側のテキストボックスが設定されていないnameため、外側のスコープから継承されます。これが、外側のボックスへの入力が内側のボックスに反映される理由です。ただし、内側のボックスに入力すると、内側のスコープに含まれるようになります。これは、外側のテキストボックスnameにバインドされてnameいないため、外側のテキストボックスが同期しないことを意味します。

修正する適切な方法は、値ではなく、スコープにモデルを保存することだけです。http://jsfiddle.net/pdgreen/5RVza/で修正しました 。秘訣は、モデルオブジェクト(data)を作成し、そのオブジェクトの値を参照することです。

間違ったコードはディレクティブのスコープを変更し、正しいコードはディレクティブのスコープのモデルを変更します。この微妙な違いにより、スコープの継承が適切に機能します。

MiškoHeveryが言ったように、スコープはコントローラーでは書き込み専用、ディレクティブでは 読み取り専用にする必要があると思います。

更新:参照:https ://www.youtube.com/watch?v = ZhfUv0spHCY#t = 29m19s

于 2013-01-23T14:16:06.673 に答える
0

構文エラーは、何かを書き間違えたことを意味します。特定のフレームワーク/ライブラリとは関係ありません。おそらく、「、」を追加するか、paranthesisを閉じるのを忘れたでしょう。もう一度チェックしてください

于 2013-01-23T14:11:48.117 に答える