狛ログ

ラベル html5 の投稿を表示しています。 すべての投稿を表示
ラベル html5 の投稿を表示しています。 すべての投稿を表示

2020年10月23日金曜日

Angular・リアクティブフォームにおけるdisabled属性の扱いについて。

10月 23, 2020

はじめまして、オフィス狛 技術部のpinoと申します。

今回は、Angularのリアクティブフォームにおけるdisabled属性の扱いについて書いてみたいと思います。

先日、Angularの実装中に以下のWarningに出会いました。
It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true
when you set up this control in your component class, the disabled attribute will actually be set in the DOM for
you. We recommend using this approach to avoid 'changed after checked' errors.

Example:
form = new FormGroup({
     first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
     last: new FormControl('Drew', Validators.required)
});

(かなり砕いた感じに)意訳すると、リアクティブフォームを使っているのに、disabled属性をHTMLに直に設定していませんか?例の書き方ならdisabled属性をDOMで設定することができます!といった具合でしょうか。

Warningなので最悪このままにしておいてもいいかもしれませんが、できることなら解消しておきたいですよね。

上記のWarningは、文言に忠実に従うことで回避できます。
以下、応用も含めて例を紹介します!

Formの定義

修正前は、以下のFormを定義していることにします。
(わかりやすく、Warningの文中にあった例を流用したいと思います。)
HTML
... // 中略

  <form [formGroup]="form">
    <input type="text" disabled formControlName="first">
    <input type="text" formControlName="last">
  </form>

...
TS
... // 中略

  form = new FormGroup({
    first: new FormControl('Nancy', Validators.required),
    last: new FormControl('Drew', Validators.required)
  });

...
FormBuilderを使用する場合
... // 中略

  form = this.fb.group({
    first: ['Nancy', Validators.required],
    last: ['Drew', Validators.required]
  });

  constructor(private fb: FormBuilder) { }

...
* FormBuilderを使用する場合は、DIが必要です。 以降は、記述を省略します。

Warningの出る書き方

HTMLで以下のようにdisabled属性を設定していると、上記のWarningが出ます。
例)
  // ①HTMLの書き方そのまま
  <input type="text" disabled>

  // ②バインディング構文使用、設定値は固定
  <input type="text" [disabled]="true">

  // ③バインディング構文使用、設定値は可変
  <input type="text" [disabled]="form.invalid">

③もダメなんですね...。


解消方法

1. 基本に従う
Warningの文言にある通りに書き換えます。
HTML
... // 中略

  <form [formGroup]="form">
    <input type="text" formControlName="first">
    <input type="text" formControlName="last">
  </form>

...
TS
... // 中略

  form = new FormGroup({
    first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
    last: new FormControl('Drew', Validators.required)
  });

...

HTMLからdisabledの記述を無くし、
コンポーネント側に {value: 'Nancy', disabled: true} という記述を増やしました。
ちなみにdisabled: trueで非アクティブ、disabled: falseでアクティブとなります。

FormBuilderを使用する場合は、以下となります。
... // 中略

  form = this.fb.group({
    first: [{value: 'Nancy', disabled: true}, Validators.required],
    last: ['Drew', Validators.required]
  });

...
こちらも、{value: 'Nancy', disabled: true} を追記すればOKです。

2. 動的に設定する
動的に切り替えたい時の方法です。
HTML
... // 中略

  <input type="text" formControlName="first">
  <input type="text" formControlName="last">
  <input type="checkbox" (click)="switchDisabled()">チェックするとfirstが非アクティブになります

...
TS
... // 中略

  isDisabled = true;

  form = this.fb.group({
    first: [{value: 'Nancy', disabled: this.isDisabled}, Validators.required],
    last: ['Drew', Validators.required]
  });

...

  switchDisabled() {
    if (this.isDisabled) {
      this.form.controls.address.enable();
    } else {
      this.form.controls.address.disable();
    }
    this.isDisabled = !this.isDisabled;
  }

...

切り替え用のチェックボックスを置いてみました。
ポイントは、コンポーネント側のenable()disable()です。
これにより、アクティブ・非アクティブを切り替えることができます。

今回はチェックボックスを使用しましたが切り替えるためのトリガーはなんでもOKですし、
切り替えが必要ない場合は、ngOnInit()に処理を置いて初期状態の判断に使用するのも良さそうです!

補足

ここまで説明してきましたが、実はdisabledをこのように指定しなくてもWarningが出ない要素もあります。
今のところそのように把握しているのは、button要素とoption要素です。

さらに、前述したWarningの出る書き方の例でいうと

button要素 → ①, ②, ③ どの書き方をしても怒られない
option要素 → ①は怒られる。②と③なら怒られない

という結果になりました。

この辺りは、余裕ができたらもう少し詳しく調べてみたいですね。


今回はここまで。
簡単な内容だったと思いますが、参考になれば嬉しいです。

2018年3月3日土曜日

各ブラウザにおけるinput要素date型(<input type="date">)の表示

3月 03, 2018

オフィス狛 技術部です。

一昔前は、Webシステムのカレンダー入力フォームと言えば、jQuery UI Datepicker が定番でした。
HTML5が使われ始めてからは、新たに追加された input要素のdate型(<input type="date">)を使う事が増えてきました。
ただ、ブラウザによって表示が微妙に異なるので、毎度問い合わせが発生します。 今回、備忘録も兼ねて、各ブラウザでどう表示されるかまとめてみました。

※(2019/07/03 修正:画像リンクがきれていたので、画像リンクを更新しました。このタイミングで、全ブラウザ最新の状態でキャプチャを撮り直しています。)

※  (2021/06/23 修正:Safariでの<input type="date">の表示が変更されていましたので、キャプチャと説明を更新しました。)


・初期値無し(<input type="date" value="">)


Internet Explorer 11
IEでは、<input type="text"> と同様の表示になります。


Microsoft Edge
初期値無しの場合、「yyyy/mm/dd」と表示されます。
ドラム式のUIで、日付を選択します。


Google Chrome(Windows)
初期値無しの場合、「年/月/日」と表示されます。
カレンダーUIで、日付を選択します。


Firefox(Windows)
初期値無しの場合、「yyyy/mm/dd」と表示されます。
カレンダーUIで、日付を選択します。


Google Chrome(Mac)
初期値無しの場合、「年/月/日」と表示されます。
カレンダーUIで、日付を選択します。


Firefox(Mac)
初期値無しの場合、「yyyy/mm/dd」と表示されます。
カレンダーUIで、日付を選択します。


Safari(Mac)
 
初期値無しの場合、表示した当日の日付が「yyyy/mm/dd」形式で表示されます。
カレンダーUIで、日付を選択します。


・初期値有り(<input type="date" value="2018-01-01">)

初期値の設定は value に表示したい日付を入力する。
※value の形式は yyyy-mm-dd である必要があります。
初期値無しの表示形式が yyyy/mm/dd となっていますが、実際に value に yyyy/mm/dd 形式で設定しても表示されません。
また、存在しない日付を value に入力しても初期値として設定されません。



Internet Explorer 11
valueに設定した値がそのまま表示されます。
IEはテキストボックスになってしまうので、文字を入力しても表示されます。


Microsoft Edge
valueに設定した日付が選択状態で表示されます。


Google Chrome(Windows)
valueに設定した日付が選択状態で表示されます。


Firefox(Windows)
valueに設定した日付が選択状態で表示されます。


Google Chrome(Mac)
valueに設定した日付が選択状態で表示されます。


Firefox(Mac)

valueに設定した日付が選択状態で表示されます。


Safari(Mac)
valueに設定した日付が選択状態で表示されます。


・スマートフォンのブラウザでの表示


Android




iPhone



IEとSafariでは普通のテキストボックス形式で表示されてしまうので、注意が必要です。
ブラウザごとに UI に微妙に違いがあることを忘れないようにしたいですね。