はじめに
Angular6 + bootstrap4 でフロント開発中。
普段は、できるだけテンプレート駆動フォームで開発しています。
この度、セレクトボックスで複数選択可能のかっちょいい見た目にしたく、@ng-select/ng-select
を導入し実装した際に、バリデーションチェックのコメント表示でハマったのでそのへん含めてまとめています。
@ng-select/ng-select
の詳しい使い方はこちらを参照。
※全く別のパッケージでng-select
という名前のものもあるので気をつけてください!
テキストエリア
普段はこんな感じで、required
といったAngularの標準バリデーションチェック機能を利用しています。
エラー時のメッセージはbootstrapのinvalid-feedback
のデザインを適用して表示しています。
<div class="form-group row">
<label class="col-sm-3 col-form-label" for="userEmail">ユーザメールアドレス</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="userEmail" [(ngModel)]="user.user_email" #userEmail="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && userEmail.invalid }" required email/>
<div *ngIf="f.submitted && userEmail.invalid" class="invalid-feedback">
<div *ngIf="userEmail.errors.required">この項目は必須です。</div>
<div *ngIf="userEmail.errors.email">メールアドレスの形式で入力してください。</div>
</div>
</div>
</div>
ng-selectを適用したセレクトボックス
前述の通り、@ng-select/ng-select
を使ってセレクトボックスの機能&見た目を拡張しているのですが、テキストエリアのバリデーションと同じようにできるだろうと思っていたら意外とハマりました。。
まず、完成形です。
<div class="form-group row">
<label class="col-sm-3 col-form-label" for="account">アカウント選択</label>
<div class="col-sm-9">
<ng-select [items]="accounts | async" name="account" bindLabel="name" autofocus bindValue="id"
[(ngModel)]="user.account_id" required #account="ngModel" (change)="changeAccount($event)"></ng-select>
<div *ngIf="f.submitted && account.invalid" class="invalid-feedback d-block">
この項目は必須です。
</div>
</div>
</div>
accounts: Promise<any>; // ほんとはanyダメよ
public ngOnInit() {
this.accounts = this.accountService.getData();
}
注意点1
・導入時のハマりポイント!
これはあくまで私の環境だけの可能性もありますので、適宜読み替えてください。
- angular.jsonにcssのパスを記載しても適用されない
→公式にできるって書いてるのにできませんでした。。
結局、公式のアナウンス通り、styles.scssにimport文を書くと無事適用されました。
- module.ts を分割していると適用範囲がわかりにくい
こちらは、ng-select
を適用したいcomponentの直近のmodule.ts
にng-selectをimportしないとエラー出ちゃいました。
注意点2
・バリデーションチェック時のcssを追記する必要がある!
公式にアナウンスがあったのですが、私が読み飛ばしていました。。
ng-select.ng-invalid.ng-touched .ng-select-container {
border-color: #dc3545;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 3px #fde6e8;
}
基本的にng-selectでもrequired
などのバリデーションチェックパラメータは有効です。
しかし、バリデーションチェックにかかったときに付与されるクラスが、ng-invalid
というクラスに変わるのでそこが注意ポイントです。
もちろん、bootstrapの標準ではないので、自分で追記する必要があります。
注意点3
・invalid-feedback
が効かない!
注意2のバリデーションチェック時のクラス名が変わることが分かっていればすぐ解決できたのですが、ハマってしまいました。。
bootstrap4によるとinvalid-feedback
は、.is-invalid
や.is-valid
に反応してスタイルを 適用する/しない を制御してるみたいです。
ng-selectは、対象となるセレクトボックスのオブジェクトに対して、Angularのinvalidパラメータは付与してくれますが、bootstrapの.is-invalidは付与してくれないようです。
しかし、セレクトボックスのエラーメッセージだけcss書くなんてやりたくないので、調べていると、.d-block
というのを見つけました。
これは、強制的にinvalid-feedback
を有効化してくれるクラスらしく、こいつを使うことで、
div要素の出し入れは通常通りAngularのngIfディレクティブにまかせて、エラーメッセージの適用はbootstrapという形ができました。
<div *ngIf="f.submitted && account.invalid" class="invalid-feedback d-block">
この項目は必須です。
</div>
さいごに
セレクトボックスにこだわったあまり、@ng-select/ng-select
と戦ったよって話でした。
サードパーティ製のフォーム系パッケージを使うときは、いろんなものとバッティングすることを考えて技術選択しないとだな、と反省しました。