サンプルコードを使ってAngularJSカスタムディレクティブのスコープ設定方法を確認し、まとめました。
デモとコードサンプルはこちら。
※目次をクリックすると目次の下部にコンテンツが表示されます。
親スコープと共有(デフォルト) scope: false
scope属性を明示的に指定していない場合のデフォルトは
scope: false
で、カスタムディレクティブは親(このサンプルコードでは”scopeCtrl”コントローラ)のスコープを使用し、自由に更新することも出来ます。
$scope.nameは親のコントローラ内で初期値を設定していますが、ディレクティブ内で設定したng-modelによって親で定義した$scope.nameを更新する事が出来ます。
(コントローラ)
$scope.name = “カメラ”;
(ディレクティブ)
フィルター: <input ng-model=name />
このサンプルのように一つのコントローラ内に複数のカスタムディレクティブを使用している場合は、すべてのカスタムディレクティブが親のスコープを共用する形になるので、片方のディレクティブのテキストボックスに値を入力したとしても残りのディレクティブにも反映されてしまい、同じ動作となってしまいます。
scope: false
で、カスタムディレクティブは親(このサンプルコードでは”scopeCtrl”コントローラ)のスコープを使用し、自由に更新することも出来ます。
$scope.nameは親のコントローラ内で初期値を設定していますが、ディレクティブ内で設定したng-modelによって親で定義した$scope.nameを更新する事が出来ます。
(コントローラ)
$scope.name = “カメラ”;
(ディレクティブ)
フィルター: <input ng-model=name />
このサンプルのように一つのコントローラ内に複数のカスタムディレクティブを使用している場合は、すべてのカスタムディレクティブが親のスコープを共用する形になるので、片方のディレクティブのテキストボックスに値を入力したとしても残りのディレクティブにも反映されてしまい、同じ動作となってしまいます。
子スコープ scope: true
scope: true
と指定すると親のスコープを継承した上でカスタムディレクティブ専用に新しい子スコープを生成します。
親スコープを継承しているのでサンプルコードでは初期状態は1)と同様の状態です。
片方のカスタムディレクティブのテキストボックスに値を入力するとディレクティブ毎にスコープが分けられているので残りのカスタムディレクティブには影響を与えず、独立して動作させる事が出来ます。
親スコープの内容は子スコープに同期され反映されますが、子スコープで変更した内容は親スコープには反映しません。
と指定すると親のスコープを継承した上でカスタムディレクティブ専用に新しい子スコープを生成します。
親スコープを継承しているのでサンプルコードでは初期状態は1)と同様の状態です。
片方のカスタムディレクティブのテキストボックスに値を入力するとディレクティブ毎にスコープが分けられているので残りのカスタムディレクティブには影響を与えず、独立して動作させる事が出来ます。
親スコープの内容は子スコープに同期され反映されますが、子スコープで変更した内容は親スコープには反映しません。
隔離スコープ
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)”関数を実行する事が出来ます。
親スコープから属性を継承せず隔離されたスコープを定義します。親スコープからの影響が無いので、アプリを問わず広い範囲で再利用する場合は、このスコープを指定する事が推奨されます。
指定方法はオブジェクトのハッシュとして指定します。
①完全に隔離
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)”関数を実行する事が出来ます。
AngularJSの特徴、仕組み
ビルトインディレクティブ
- ビルトインのディレクティブの概要
- データバインディングのディレクティブの概要
- ng-repeatを使ってリスト、テーブル、フィルター
- ng-includeを使って別のHTMLファイルを埋め込み
- ng-switchを使って内部にあるHTMLテンプレートの表示を切り替え
- ng-if、ng-show、ng-hideを使って表示、非表示を切り替え
- ng-class、ng-styleを使ってCSSを設定
- イベント処理
- 有効、無効を切替えるディレクティブ
- フォームの入力チェックを行い、動的にCSS追加
- ng-optionsを使ってSelectメニューを作成
- ng-repeatを使ってラジオボタンを作成
- ビルトインのフィルターの使用方法
- ビルトインのフィルターで関数を使用
- カスタムフィルターの使用方法
- Bootstrap3を使ってページング
- スクリプト内でフィルターを使用、既存のフィルターを拡張
サービス
- サービスの概要とfactory、service、providerの使い分け
- $qサービスでpromise/deferredパターン
- $httpサービスの概要、サーバーからJSONデータ取得
- $httpサービスのPOSTでデータ送信
- $qサービスを使ってhttpリクエストを複数実行
- $httpサービスのinterceptorの使用方法
- AngularJSのwithCredentialsの設定、CORS
- $timeoutサービスと$intervalサービス
- $resourceサービスを使ってREST
- $locationサービスを使ってURLを操作
- $routeサービスと$resourceサービスを使ったサンプルを作成
- routeChangeSuccessを使ってflashメッセージ表示
- JavaScript、CSSを含むHTMLデータをバインドして表示
カスタムディレクティブ
AngularJSの特徴、仕組み
ビルトインディレクティブ
- ビルトインのディレクティブの概要
- データバインディングのディレクティブの概要
- ng-repeatを使ってリスト、テーブル、フィルター
- ng-includeを使って別のHTMLファイルを埋め込み
- ng-switchで内部にあるHTMLテンプレートの表示を切り替え
- ng-if、ng-show、ng-hideを使って表示、非表示を切り替え
- ng-class、ng-styleを使ってCSSを設定
- イベント処理
- 有効、無効を切替えるディレクティブ
- フォームの入力チェックを行い、動的にCSS追加
- ng-optionsを使ってSelectメニューを作成
- ng-repeatを使ってラジオボタンを作成
- ビルトインのフィルターの使用方法
- ビルトインのフィルターで関数を使用
- カスタムフィルターの使用方法
- Bootstrap3を使ってページング
- スクリプト内でフィルターを使用、既存のフィルターを拡張
サービス
- サービスの概要とfactory、service、providerの使い分け
- $qサービスでpromise/deferredパターン
- $httpサービスの概要、サーバーからJSONデータ取得
- $httpサービスのPOSTでデータ送信
- $qサービスを使ってhttpリクエストを複数実行
- $httpサービスのinterceptorの使用方法
- AngularJSのwithCredentialsの設定、CORS
- $timeoutサービスと$intervalサービス
- $resourceサービスを使ってREST
- $locationサービスを使ってURLを操作
- $routeサービスと$resourceサービスを使ったサンプルを作成
- routeChangeSuccessを使ってflashメッセージ表示
- JavaScript、CSSを含むHTMLデータをバインドして表示
カスタムディレクティブ