AngularJS1.5を使っていて、transcludeで中に要素を埋め込むようなコンポーネントで、その埋め込まれる要素内からコンポーネントが提供する機能にアクセスする、ということをしたかった。例えばダイアログ的な枠組みを提供するコンポーネントでtranscludeで内容を埋め込めて、その中のボタンからダイアログを閉じる、みたいな。
しかしtranscludeされる要素は枠組みのコンポーネントとは別の孤立したスコープになってしまい、コンポーネントにはアクセスできないようだった。アクセスさせるにはディレクティブのlink
でtransclude
の制御をする必要があるようだ。
利用側
// Application |
my-dialog
がダイアログを提供するディレクティブだとして、その中にレイアウトを記述したものが埋め込まれる、という想定transclude
される要素内からダイアログが提供するcloseDialog()
という関数を呼び出して、ディレクティブ側に通知するtransclude
外からはその機能は呼べない
ディレクティブ側
// Directive using transclude |
angular
のcomponent
だとスコープやコントローラにアクセスする方法がわからなかったので、directive
として作成transclude: true
でトランスクルードを有効にするtemplate
内でng-transclude
を使って埋め込むと、孤立したスコープでtransclude
要素が埋め込まれてしまってアクセスする方法がないため、link
関数の第5引数のtranscludeFn
を使用してtransclude
する要素をクローンして自前で目的の場所に埋め込む- その際のスコープはディレクティブのスコープの親から
$new
して、ディレクティブとは別のスコープにしておく - その新しいスコープに提供したい関数(
closeDialog
)を定義してやることでtransclude
内から参照できるようになる
- その際のスコープはディレクティブのスコープの親から
デモ
http://plnkr.co/edit/ADbo0K?p=preview
その他
- スコープは廃止される、ということなのであまりよくない方法かも…
- 試してないけどAngular2の場合には外側のコンポーネントから
@ViewChild
で内側のコンポーネントのコントローラが取得できるので、それ経由でアクセスすればそさそう- AngularJS1.5でも同じようにできなくはないが、親から子コンポーネントへのアクセスが面倒なのがネック
リンク
- AngularJS: Developer Guide: Directives#Creating a Directive that Wraps Other Elements
scope: {}
でディレクティブ独自のスコープを作らない場合、外側のスコープを書き換えることになるので一応transclude内からアクセスできるようにはなるが、スコープが汚染されてしまう
- AngularJS: API: $compile:
link
の説明あり - Transclusion and scopes - Angular Tips