angular2で再帰的に親directiveを辿りたいときってありますよね?そういうときは@Optional
, @Host
, @SkipSelf
を使いましょう。
ネストしている数を表示するFooDirective
を作りながら説明します。
//our root app component
import {Component} from 'angular2/core'
import {FooDirective} from './foo'
@Component({
selector: 'my-app',
providers: [],
template: `
<div>
<h2>Hello {{name}}</h2>
<div foo #a="foo">
{{a.nestCount}}
<div foo #b="foo">
{{b.nestCount}}
<div foo #c="foo">{{c.nestCount}}</div>
</div>
</div>
</div>
`,
directives: [FooDirective]
})
export class App {
constructor() {
this.name = 'Angular2'
}
}
とりあえず雛形を作ってみる
こんなかんじですか
import {
Directive,
Optional,
Host,
SkipSelf
} from 'angular2/core'
@Directive({
selector: '[foo]',
exportAs: 'foo'
})
export class FooDirective {
// なんとかして親のFooDirectiveをinjectしたい
constructor(private _parent: FooDirective) {}
get nestCount() {
return this._parent ? this._parent.nestCount + 1 : 0;
}
}
@Host
@Host
アノテーションをつけると、自分自身の要素からShadow DOM root間を辿って指定された型のdirectiveをinjectしてくれます。とりあえずFooDirective
型のdirectiveを_parent
にinjectしてみます。
export class FooDirective {
constructor(@Host() private _parent: FooDirective) {}
// ...
}
怒られました。自分自身の要素も含まれるので循環参照となります。
EXCEPTION: Cannot instantiate cyclic dependency! (FooDirective -> FooDirective)
@SkipSelf
@SkipSelf
アノテーションをつけると、自分自身の要素は除外して辿ってくれます。以下のように書き換えてみます。
export class FooDirective {
constructor(@Host() @SkipSelf() private _parent: FooDirective) {}
// ...
}
また怒られました。辿った結果directiveがないとエラーになります(つまり一番上のFooDirective
ではエラー)。
EXCEPTION: No provider for FooDirective! (FooDirective -> FooDirective)
@Optional
@Optional
アノテーションをつけると、辿った結果directiveが存在しなければnull
がinjectされます。コードを以下のように書き換えて完成です。http://plnkr.co/edit/9CwZnm?p=preview こんな感じで動いたでしょうか?
export class FooDirective {
constructor(@Optional() @Host() @SkipSelf() private _parent: FooDirective) {}
// ...
}
思ったこと
初めて見たときは気持ち悪い書き方だと思ったw