こんにちは、オフィス狛 技術部の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