フリーランスエンジニア・プログラマのみなさんは、普段どちらでお仕事をされていますか? 自宅だとなかなか作業が捗らない。たまには場所を変えてリフレッシュして仕事をしたい。そんな思いで自宅以外の仕事場を求めている方も多いので […]
SEROKUを支える技術 Angular Tips編 その3
さて、今回は前回予告したとおり ng-content
を使った、テンプレートに対して外部から子要素を突っ込むような処理を書いてみようかと思います。
[adinserter block="1"]
Angularに置いてあまりサンプル記事がない印象ですが、使い方さえ覚えておけばきっと役に立つはずです!
目次
Tips4 :ng-contentを使った子要素への注入
ng-contentとは、作成したコンポーネントに対して外部から要素を注入するときに使うタグです。
ng-contentを使ったシンプルな例
まずは一番簡単な例を、コードベースで書いていきたいと思います。
-
- selector: 'foo' とするFooコンポーネントを定義
<div> <h1>header要素</h1> <!-- 以下ng-contentを配置し、外部から注入するための要素を宣言 --> <ng-content></ng-content> </div>
- 外部のコンポーネントでfooを呼び出し、さらに要素を注入
<foo> <div>test</div> <span>test2</span> </foo>
- selector: 'foo' とするFooコンポーネントを定義
-
- 上記のfooコンポーネントを呼び出した結果のhtml
<div> <h1>header要素</h1> <!-- angularによって展開され、fooタグに書いたタグが全てng-contentに展開される --> <div>test</div> <span>test2</span> </div>
- 上記のfooコンポーネントを呼び出した結果のhtml
fooタグ内部に書いた要素が、まるまるng-contentと置き換わりますね。
上記の簡単な例を実装する上ではうまくいきましたが、では複数の要素を別々の場所に注入したい場合はどうすればよいでしょう?
[adinserter block="1"]
ng-contentを使い複数の要素を注入する例
ng-contentではselectアトリビュートを使い、注入するコンテンツを指定することができます。
以下のコードで複数の要素を注入したいと思います。
-
- selector: 'foo' とするFooコンポーネントを定義
<div> <!-- ng-contentを宣言(selectでh1を指定) --> <ng-content select="h1"></ng-content> <!-- ng-contentを宣言(selectで.headerを指定) --> <ng-content select=".header"></ng-content> <!-- 以下ng-contentを宣言(select無し) --> <ng-content></ng-content> </div>
- 外部のコンポーネントでfooを呼び出し、さらに要素を注入
<foo> <h1>test</h1> <div class="header">test2</div> <div>test3</div> <span>test4</span> </foo>
- 上記のfooコンポーネントを呼び出した結果のhtml
<div> <!-- selectでh1を指定しているのでh1タグの要素が展開される --> <h1>test</h1> <!-- selectで.headerを指定しているのでheaderクラスを指定した要素が展開される --> <div class="header">test2</div> <!-- 上記指定に当てはまらないタグが全てng-contentに展開される --> <div>test3</div> <span>test4</span> </div>
- selector: 'foo' とするFooコンポーネントを定義
fooタグ内部に書いた要素の中で、Fooコンポーネントのng-contentのselectで指定した箇所にそれぞれ置き換わりますね。
ちなみに、上記の例で言うとh1タグが複数あった場合、またはheaderクラスが複数あった場合でも、selectにマッチする要素分ng-contentは置き換わります。
[adinserter block="1"]
ng-contentを使った例 応用編
上記の例はあくまでただの使い方の例だったので、どういう時に役に立つかをユースケースを交えながら書いていきたいと思います。
一つの例として、コンポーネントを作る際に、あるボタンイベントを親コンポーネントにEventEmitterを使って通知し、実際の処理は親コンポーネントでやらせているケースがあるとします。
- selector: 'foo' とするFooコンポーネントを定義
// テンプレート側 <div> <button (click)="clickHandler()"></button> </div> // コンポーネント側 @Output() onClicked = new EventEmitter(); clickHandler() { onClicked.emit(); }
- 外部のコンポーネントでfooを呼び出しonClickedに対してイベントハンドラを仕掛けている
// テンプレート側 <foo (onClicked)="clickHandler()" ></foo> // コンポーネント側 clickHandler() { // 実際の処理 }
Fooコンポーネント側のclickHandlerで、なにか特別なことをしているのなら別ですが、ただemitしているだけならば以下のように書いたほうが、Fooコンポーネントはロジックを気にせずにただのViewテンプレートとしての役割に専念できるので見通しが良いです。
- selector: 'foo' とするFooコンポーネントを定義
// テンプレート側 <div> <ng-content select="button"></ng-content> </div> // コンポーネント側 処理がなくなる!!
- 外部のコンポーネントでfooを呼び出しclickハンドラを設定しているbuttonタグを要素として注入
// テンプレート側 <foo> <button (click)="clickHandler()"></button> </foo> // コンポーネント側 clickHandler() { // 実際の処理 }
上記は一例に過ぎませんが、同じような状況は結構ある気がします。
これ使ったほうがコードがキレイになりそうというのがもしあれば試してみると良いかもしれません。
[adinserter block="1"]
まとめ
今回は ng-content
に関して書きました。
前回の記事でngTemplateOutlet
にも少し触れましたが、ある特定の要素を置き換えるという場合にも複数のやり方がありますね。
(もちろんそれぞれで適切な使い所は異なりますが)
吐き出したいネタが一旦尽きてしまったので、なにか思いついたらまたアップしたいと思います。
それでは皆さんごきげんよう。
[adinserter block="1"]
>SEROKUを支える技術 ~開発準備編~
>SEROKUを支える技術~プロジェクト管理編~
>SEROKUを支える技術~社内 Kubernetes 編~
>SEROKUを支える技術~CI/CD編~
>SEROKUを支える技術~社内 Kubernetes トラブルシュート前編~
>SEROKUを支える技術 Angular Tips編 その1
>SEROKUを支える技術 Angular Tips編 その2
>SEROKUを支える技術 Angular Tips編 その3