はまったりひらめいたり…とか…

.Net系プログラムで勉強したこととか嵌ったことについて書いたりします。

エンプラ脳でAngularのReactiveFormsを使ってみる

AngularのReactiveFormsは素敵なFormModuleだと思います。

自分も実際の作業の際には非常にお世話になりました。

ReactiveFormsについて

https://angular.io/docs/ts/latest/guide/reactive-forms.html

https://angular.io/docs/ts/latest/cookbook/form-validation.html

上記のAngularの公式サイトが大変参考になります。

基本のキは、上記サイトで学習できるので、エンプラ脳でReactiveFormsの利用方法を考えてみようと思います。

記事作成当時のAngularはV4です。

あと、これベストプラクティスかどうかはかなり怪しいので、色々ご意見いただけるとありがたいです。

Formでほしい機能を考える

さて、エンプラな頭で考えたとき、WebApplicationは同じような機能の複数の入力Formを持つかとおもいます。

入力Formは複数あれど、それぞれの画面で共通してほしい機能は存在するはずです。

さくっと考えて下記な感じでしょうか。

  1. Validarionエラーチェック
  2. エラーメッセージ
  3. ページ遷移時の挙動
  4. データ確定処理

同一の機能であれば、これらを共通のロジックでまとめて作りたい!

で、複数のComponentでまとめて使いたい!

ということで、作ってみようと思います。

結果、下図のような動きになります。色々サボってるので動きがちょいアレですが…

f:id:TakasDev:20170614152820g:plain

Validartionエラーチェック

これは、Angularの公式リファレンスにかかれているとおりの機能ですね。

ただ、各Componentで共通した機能として作りたいので、ReactiveFormsの諸々の処理を実装したBaseClassを作成します。

各ComponentでBaseClassをExtendsしてValidationの処理を書かなくていい感じに仕上げます。

Angular v4 ReactiveFormのやつ

また、Validationの設定を全部ComponentClassの中に書いていくのも邪魔くさいので

ValidationのSetting部分を切り出します。

Angularv4ReactiveFormのやつ

作成するComponentでBaseComponentをExtendsして、上記で作成したValidarionのセッティングを読み込みます。

Angularv4ReactiveFormのやつ

BaseComponentで、ValidationCheckに必要な作業をほぼ行っているので

実際のComponentに記述する量はガクッと減るかと思います。

getterでValidationSettingのコントロール名を返しているのは、ComponentのHtml内で楽に使用するためです。

HTMLは下記のような作りになっています。

地味に、AngularMaterialを使用して実装しています。

gistf9b185b48afceca9c50a04637a200300

formControlのNameの定義部分が[formControlName]となっているのが地味な味噌ですね。

エラーメッセージを格納しているformErros等の指定も、上記のようにしています。

ValidationSettingで設定しているCONSTのキーワード値を変更すると、関連項目のすべてに適用されるため

「DBの項目名称と一致してなかったテヘペロ」って場合も、最小限の変更で適切な箇所に変更を波及されます。

エラーメッセージ

エラーメッセージについては、

「必須ですよ」とか「文字列Overですよ」とか一般的なエラー内容は集約して管理したいので

エラーメッセージ生成Classを作成しました。

Static宣言してnewなしで使えるようにしています。

Angularv4ReactiveFormのやつ

ページ遷移時の処理

入力中にページ遷移する場合、「いいの?」ってダイアログ出したい時があります。

そんな場合は、RouterのCanDeactivateを使用するのが良いですね。

下記の感じで作成しました。

Angularv4ReactiveFormのやつ

CanDeactivateを使用する際にGenericsにComponent型を突っ込みます。

その際、BaseComponentを継承して作成されたComponentと指定することで

Activate判断処理において、Component内の処理を呼び出せるようにします。

Componentの「canDeActivateInputPage」処理では、独自のダイアログをだすなり

何かの条件のときのみ確認するなり、よしなに処理を実装します。

今回はBaseComponentに処理を記述しましたが、継承先のComponentごとに実装をバラすこともできます。

Routerでは下記のように設定し、ページ遷移時に上記で作成したGuard処理が実行されるようにします。

Angularv4ReactiveFormのやつ

データ確定時の処理

初っ端開いた状態だと、formはCleanな状態です。

Submitが走るとエラー状態にはなるものの

ValueChangeイベントが走らないため、FormsErrorsにエラー内容が格納されません。

なので、内部の全項目をDirty状態にして、ValidationCheckをあえて走らせる処理を実装します。

上記BaseComponentの↓の実装部分ですね。

    allControlReCheck() {
        for (const field in this.formErrors) {
            const control = this.inputForm.controls[field];
            control.markAsDirty();
            this.onValueChange();
        }
    }

あとは複製…

ValidationSettingとHtmlとComponentについては

画面に設定する項目に関するものだけを変更すれば、新しい画面が比較的ラクに作れるようになります。

最後に

今回作成したソースは下記リポジトリで管理しています。

github.com