AngularJSカスタムディレクティブのスコープ設定方法

サンプルコードを使ってAngularJSカスタムディレクティブのスコープ設定方法を確認し、まとめました。

デモとコードサンプルはこちら
 

(1)親スコープと共有(デフォルト) scope: false


 
scope属性を明示的に指定していない場合のデフォルトはscope: falseで、カスタムディレクティブは親(このサンプルコードでは”scopeCtrl”コントローラ)のスコープを使用し、自由に更新することも出来ます。
 
$scope.nameは親のコントローラ内で初期値を設定していますが、ディレクティブ内で設定したng-modelによって親で定義した$scope.nameを更新する事が出来ます。
(コントローラ)
$scope.name = “カメラ”;
 
(ディレクティブ)
フィルター: <input ng-model=name />
 
このサンプルのように一つのコントローラ内に複数のカスタムディレクティブを使用している場合は、すべてのカスタムディレクティブが親のスコープを共用する形になるので、片方のディレクティブのテキストボックスに値を入力したとしても残りのディレクティブにも反映されてしまい、同じ動作となってしまいます。
 

(2)子スコープ scope: true


 
scope: trueと指定すると親のスコープを継承した上でカスタムディレクティブ専用に新しい子スコープを生成します。
 
親スコープを継承しているのでサンプルコードでは初期状態は1)と同様の状態です。
 
片方のカスタムディレクティブのテキストボックスに値を入力するとディレクティブ毎にスコープが分けられているので残りのカスタムディレクティブには影響を与えず、独立して動作させる事が出来ます。
 
親スコープの内容は子スコープに同期され反映されますが、子スコープで変更した内容は親スコープには反映しません。
 

(3)隔離スコープ


 
1)隔離スコープの概要
 
親スコープから属性を継承せず隔離されたスコープを定義します。親スコープからの影響が無いので、アプリを問わず広い範囲で再利用する場合は、このスコープを指定する事が推奨されます。
 
指定方法はオブジェクトのハッシュとして指定します。
 
①完全に隔離
 
scope: {}
 
②1Wayバインディング
 
(カスタムディレクティブ内の定義)
scope: { localName:’@myAttr’ }
 
(カスタムディレクティブを適用)
<widget my-attr=”{{name}}”>
 
scope: { localName:’@myAttr’ }と設定する事によって、カスタムディレクティブのローカルスコープの属性(localName)をDOM属性(myAttr)の値にバインドします。
 
{{name}}と記述する事によって親スコープのname変数の値を1方向バインディングする事が出来ます。
 
DOM属性の値は文字列なので、このバインドの結果は文字列になることに注意します
 
③2Wayバインディング
 
(カスタムディレクティブ内の定義)
scope: { localModel:’=myAttr’ }
 
(カスタムディレクティブを適用)
<widget my-attr=”parentModel”>
 
・scope: { localModel:’=myAttr’ }と設定する事によって、カスタムディレクティブのローカルスコープの属性(localModel)を指定した名前の属性(myAttr)を介して親スコープの変数(parentModel)と双方向バインドする事が出来ます。
 
・この場合は、文字列ではなくJSONオブジェクトとして取り扱われ、実際のスコープモデルが属性にバインドされます。
 
④親スコープの関数を実行
 
(カスタムディレクティブ内の定義)
scope: {localFn:’&myAttr’}
 
(カスタムディレクティブを適用)
<widget my-attr=”prtFnc(prm)”>
 
・scope: {localFn:’&myAttr’}と設定する事によって、カスタムディレクティブのローカルスコープの属性(localFn)を指定した名前の属性(myAttr)を介して親スコープの関数(prtFnc)実行する事が出来ます。
 
2)サンプルコードの概要
 
①完全隔離スコープ
 
(定義)
scope: {}
 
親スコープで定義した商品リストを取得する事が出来ないので商品リストを表示する事は出来ません。
 
②1Wayバインディング
 
(定義)
localname: “@namescope”,
localbind: “@bindscope”
(HTML)
<div ordered-list3 namescope={{products}} bindscope={{parebind}}></div>
(カスタムディレクティブのテンプレート)
<p>
 1Way(変数localbind): <input ng-model=localbind /><br /> データ(変数localname): {{localname}}
</p>
 
●親スコープで定義した商品リストが表示されるか?
 
親スコープで定義したproductsが1Wayバインドされますが、JSONオブジェクトではなく、一つの文字列として取得されるのでng-repeatでは処理することが出来ません。商品リスト全体を一つの文字列として表示しています。
 
●カスタムディレクティブのテキストボックスの入力結果
 
カスタムディレクティブのテキストボックスで指定したlocalbindは1Wayバインドされているので、親スコープで指定した初期値や親スコープで行った変更はカスタムディレクティブ側に反映されますが、カスタムディレクティブ内で変更した内容は親スコープに反映されません。
 
③2Wayバインディング
 
(定義)
localname: “=namescope”,
localbind: “=bindscope”
(HTML)
<div ordered-list2 namescope=”products” bindscope=”parebind”></div>
(カスタムディレクティブのテンプレート)
<p>
 2Way(変数localbind): <input ng-model=localbind /><br /> フィルター(変数key): <input ng-model=key />
 <ol><
  li ng-repeat=’item in localname | filter: key’>{{item.product_name}} : {{item.price | number:0}}円</li>
 </ol>
</p>
 
●親スコープで定義した商品リストが表示されるか?
 
親スコープで定義したproductsが2Wayバインドされるので、商品リストを表示する事が出来ます。
 
●カスタムディレクティブのテキストボックスの入力結果
 
カスタムディレクティブのテキストボックスで指定したlocalbindは2Wayバインドされているので、ここで入力した値は親スコープにも反映します。
 
④親スコープの関数を実行
 
(定義)
localfee: “&feescope”
(HTML)
<div ordered-list4 namescope=”products” bindscope=”parebind” feescope=”getFee(group)”></div>
(カスタムディレクティブのテンプレート)
<span>※{{localfee()}}<span>
 
親スコープで定義されている”getFee(group)”関数を実行する事が出来ます。

関連記事の目次

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です