こんにちは、オフィス狛 技術部のpinoです。
早速ですが、皆さんはAngularをやっていて「コンポーネントのタグに直接classを付与したいんだけどなぁ....。」と思った経験はないでしょうか。
今回は、そんな時に使える @HostBinding についてご紹介したいと思います!
準備
まずは、コンポーネントを用意します。app.component.html(親コンポーネント)
- <header class="header">
- <section class="header__about">
- <h1 class="header__title">@HostBinding Sample</h1>
- <p class="header__lead">動作確認用のサンプルです</p>
- </section>
- <nav class="header-nav">
- <ul class="header-nav__list">
- <app-list-item *ngFor="let name of names" [name]="name"></app-list-item>
- </ul>
- </nav>
- </header>
list-item.component.html
- <li class="header-nav__item">
- <input type="checkbox" />{{ name }}
- </li>
list-item.component.css
- .header-nav__item {
- width: 120px;
- height: 64px;
- padding-left: 32px;
- line-height: 64px;
- }
list-item.component.ts
- import { Component, Input, OnInit } from '@angular/core';
- @Component({
- selector: 'app-list-item',
- templateUrl: './list-item.component.html',
- styleUrls: ['./list-item.component.scss']
- })
- export class ListItemComponent implements OnInit {
- @Input() name: string;
- constructor() { }
- ngOnInit(): void {
- }
- }
ビルド後のイメージ
色味がなく、シンプルで寂しい印象です。
ここから、実際にHostBindingを使ってclassを付与してみたいと思います。
HostBindingの使い方
使い方は1. コンポーネントのタグにclassを付与する
2. 上記1に加えて、動的にclassの付け外しをする
と、主に2つあります。
まずは、1. コンポーネントのタグにclassを付与するについてです。
こちらは、大きく2通りの書き方ができます。
list-item.component.css
- import { Component, HostBinding, Input, OnInit } from '@angular/core'; // HostBinding を追加
- @Component({
- selector: 'app-list-item',
- templateUrl: './list-item.component.html',
- styleUrls: ['./list-item.component.scss']
- })
- export class ListItemComponent implements OnInit {
- @HostBinding('class') listItem = 'list-item'; // ①
- @HostBinding('class.first') first = true; // ②
- @Input() name: string;
- constructor() { }
- ngOnInit(): void {
- }
- }
ポイントは、@HostBinding()の、()の中です。
①は、「'class'」のみ指定して、なんのclassを付与するかは変数の値が使用されるパターンです。
値部分に定数を使えば、ロジック側にテンプレートの情報をベタ書きすることも避けられますね。
固定のclassであればこれで十分そうです。
②は、「'class.first'」と付与するclass名まで指定するパターンです。
この場合は、後に続いている値がtrueであれば付与、falseであれば付与しない、ということになります。
(※真偽値を固定で設定したい場合は、「@HostBinding('class.first') readonly first = true;」 といった具合に、readonlyをつけるなどの対策が考えられます。)
また、HostBindingの話とはすこし逸れますが、コンポーネントのタグに使用するclassは
グローバルである(style.cssに記述されている等)か、:hostメタデータを使用する必要があります。
今回は、自コンポーネントのCSSに背景色をつけるclassを用意したいと思います。
list-item.component.css
- // 以下を追加
- :host.list-item.first {
- background-color: #7ae5ec;
- }
- :host.list-item.second {
- background-color: #7aecc0;
- }
- :host.list-item.third {
- background-color: #7ab9ec;
- }
ここまでのビルド後イメージ
すべてのコンポーネントにclassが付与されて、背景色がつきました。
次は、2. 上記1に加えて、動的にclassの付け外しをするについてです。
list-item.component.css
- export class ListItemComponent implements OnInit {
- @HostBinding('class')
- @Input() name: string; // ①
- // 今回formは用意していないので、例としてだけ挙げます
- @HostBinding('class.valid') get valid() {
- return this.form.valid;
- } // ②
- @HostBinding('class.list-item') isClick = false; // ③-A
- ...
- onClick(): void {
- this.isClick = !this.isClick;
- } // ③-B
他にもいろいろな方法があると思うのですが、簡単に思いつくものを挙げてみました。
①は、Input()で受け取った値を使用します。
組み合わせて使うだけで、特別なことをしてる感じがします...!
②について、今回Formは用意していないので記述の例になるのですが、状態など値そのものを監視したい時に使える方法です。
getterってあまり使う機会がなかったのですが、今回試してみたところ使い勝手がいいですね!
また③は、②のようにイベント発生時ではなく、識別子に設定した変数の値を書き換えることによってclassの付け外しをしています。
ここまでで、上記の①と③をプログラムに落とし込んだビルド後のイメージが以下のようになります。
それぞれで別々のclassの付与と、classの付け替えができました!
補足
ここまでclassを付与する使い方を紹介してきましたが、なんとHostBindingはclass以外のバインディングにも使えます。例えば、「@HostBinding('style.display') flex = 'flex';」としてあげればstyle="display: flex;"がバインドされます。
便利!
今回は公式以外に以下サイトも参考にしたのですが、「HostBinding('value') myValue;は[value]="myValue"と全く同じです。」という一文が特にわかりやすかったです。
@HostBindingと@HostListener:彼らは何をし、何のためにいますか?
以上、HostBindingデコレータについて紹介しました。
参考になればうれしいです。
Angular