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

Angularや.NETやAzureやその他色々。

Reactive FormsでオリジナルのComponentを使用する

初めに

今回の記事は、下記構成でお送りします。

  • Angular: 5.1.1
  • AngularCli: 1.6.1

Reactive FormsでOriginalのComponentを使いたい

業務系のWebApp作るお仕事してるとReactive Formsを多用します。

Validatorのエラーチェック部分を楽に作れるのが気に入ってます。

ただ、DBから引っ張ってきたマスタListのSelectBoxとか

多くのところで使用するようなコントロールは共通化したいところです。

そこで、Component部品をReactive Formsで使用できないか試してみました。

まずは単純なReactive Forms

ログイン画面っぽいもの想定して、単純なReactive Formsの画面を作ってみます。

<form [formGroup]="inputForm">
  <input [formControlName]="USER_ID_KEYWORD" placeholder="ユーザーID" />
  <label style="color:red" *ngIf="formErrors[USER_ID_KEYWORD]">{{formErrors[USER_ID_KEYWORD]}}</label>
  <br/>
  <input [formControlName]="PASSWORD_KEYWORD" placeholder="パスワード" />
  <label style="color:red" *ngIf="formErrors[PASSWORD_KEYWORD]">{{formErrors[PASSWORD_KEYWORD]}}</label>
</form>

ユーザーIDコントロールだけ切り出し、別Componentに

  • ユーザーIDコントロールapp-user-id-textという名前で作成しました
<form [formGroup]="inputForm">
  <app-user-id-text [formControlName]="USER_ID_KEYWORD"></app-user-id-text>
  <label style="color:red" *ngIf="formErrors[USER_ID_KEYWORD]">{{formErrors[USER_ID_KEYWORD]}}</label>
  <br/>
  <input [formControlName]="PASSWORD_KEYWORD" placeholder="パスワード" />
  <label style="color:red" *ngIf="formErrors[PASSWORD_KEYWORD]">{{formErrors[PASSWORD_KEYWORD]}}</label>
</form>

まずは、単純に、新しく作成したComponentに

ユーザーIDで使用してたFormControlNameを使用してみます。

エラー

f:id:TakasDev:20171221220818j:plain

ですよねー。ってことで修正します。

Reactive Formsの作り方を思い出す

Reactive Formsは、ComponentのInit時に、下記のように作成したはずです。

buildForm() {
    this.inputForm = this.fb.group(this.formSetting);
    this.inputForm.valueChanges.subscribe(data => {
        this.onValueChange(data);
    });
    this.onValueChange();
}

FormのSetting情報を、FormBuilder.groupを使用して

FormGroupプロパティに突っ込んでいます。

つまり、Componentに対してFormGroupの情報を送ってやれば良いのかもしれません。

子ComponentにFormGroupのプロパティを生やす

@Input() fg: FormGroupのプロパティを生やしました。

export class UserIdTextComponent implements OnInit {

  @Input()
  fg: FormGroup;

...
}

Componentを使用する際に

<app-user-id-text [fg]="hogeForm"> ... みたいな感じで使用します。

結果

f:id:TakasDev:20171221221321g:plain

通りました。

入力内容が@InputのFormGroupを通して、親Componentに伝播し

また、オリジナルComponentのValidationエラーが

親Componentのエラーメッセージプロパティに格納されました。

最後に

今回作成したコードは、下記にあげてあります。

煮るなり焼くなりお好きにしてくださいませ。

github.com

…Angular v2時代に作った勉強用のリポジトリそろそろ名前変えないとなぁ…

Xamarin.AndroidでNfc機能の技術検証した話

この記事は

[初心者さん・学生さん大歓迎!] Xamarin その1 Advent Calendar 2017

13日目の記事となります。Advent Calendar初挑戦です。よろしくお願いします!

初めに

Xamarin.Formsはずいぶん前からちょこちょこ触ってましたが

本業はWebの方のお仕事中心で、正直まだまだ初心者の域を脱していません。

ですが、最近、Nativeの技術検証をする機会がありましたので

Xamarinで色々やってみた話です。

Xamarin.Androidの話になります。iOSまでは手を出せませんでした。

今回の記事はコードなしで感想中心となります。

コードは後述するGitHubに上げてますので煮るなり焼くなり致してくださいませ。

技術検証したこと

AndroidNfcを使用し、Suicaとかから履歴情報を引き抜く

まずはkotlin

AndroidにおけるSuicaから履歴を抜く方法については検索してすぐ見つかりました。

特に参考になったのは下記のページです。

qiita.com

qiita.com

www.kotemaru.org

が、JavaやKotlinのコードをC#に素直に変換できるか不安がありました。

なので、まずはkotlinで実装し

どのように動作するのか確認しながらC#に落とし込む手法を取りました。

基本は上記のページを参考に、kotlinの実装と動作を確認しつつ写経しました。

GitHub - Takas0522/FelicaCardReaderSample: FelicaCardReaderをKotlinで作ってみたSample

kotlinで出来上がったのが上記のコードです。

NFCAPIを使用し、Byte配列のコマンドを投げ

リクエストをByte配列で受け取る方式で、カードの履歴情報を取得します。

Xamarin.Android

はまったか?

案外、ハマる部分は少なく、素直に移行できたかと思います。

と、いうのも、NFCのやりとりで使用するNfcFクラスといったクラスの使い方は

ほぼ、kotlinのときと同様の使い方ができたので

その部分については迷うことは少なかったです。

(「Byte配列作る→投げる→Byte配列もらう」だけなので特例とは思いますが…)

なので、Xamarin特有(?)のR→Resourceとか、Intent周り等

基本的な、且つ、kotlinやJavaの記法から変わってる部分で少しハマったりしました。

最終的に、そういった基本的な部分で困ったら

Xamarin公式のドキュメントからサンプルソース落として

基本動作を抑える解決方法に落ち着きました。

kotlinで先に書いてみた恩恵

今回は特殊なケースかもしれませんが

Xamarinでうまく動作できないとき、kotlinで動作させてみて

Byte配列の変数の状態等をチェックすることもできたので

先にkotlinでコード書いてみたのが非常に活かせることができました。

Xamarinでうまく動かないときは

同様な動作をkotlin等のNativeコードで動かしてみると

色々気づきがあるかもしれません。

kotlinの書き換えが地味に多い

kotlinはオブジェクト操作周りが充実している印象で

その周りのC#の書き換えが地味に多かったです。

(Byte配列いじくることばっかやってたのでだいぶ偏った印象かも。。)

.netから見たkotlinの良さは、@amay077 さんの記事が参考になるかと思います。

qiita.com

自分は、Byte配列のここからここまでコピーする。みたいな CopyOfRange とか

Byte配列の Write ファンクションでByte配列に値を格納していくー。みたいな

Kotlin標準の機能の拡張を我慢できずに作ったりはしました。

ほかの言語に触れることでよさげな機能を発見して

C#の実装に取り込むといったことができるのも

Nativeコードに触れる良さかな。と思いました。

まとめ

  • 勉強目的ならNativeコードから書いたほうが格段に良い

    • 使用するNativeAPIの使い方が理解しておくことで、C#への移行がスムーズに。
    • kotlinで動作するものを作ることで、C#で動作しないときの比較検証ができた。
    • JXUGの勉強会ではよく耳にしますが本当に実感できました…!!
  • NativeコードからのC#への移行はあんがいあっさり行えた

    • ただし、NativeAPIをほとんど使用していない。
    • NativeAPIを多用し始めるとまた別の落とし穴が見えてくるはず
  • 基本的な部分はXamarin公式ドキュメントのサンプルで粗方洗える

    • iOSのCoreNFCとか新し目のAPIのサンプルもあったりするので結構ニッチな部分も抑えれるかも…

さいごに

今回作成したXamarin.Androidのコードは下記になります。

GitHub - Takas0522/FelicaCardReaderSampleXamarin

明日のAdventCalendarは @masanori-_-msl さんです。

よろしくお願いします!

AzureのVMと自社サーバーをVPNでつなげて(かんたんな)Deployをしてみる

実験的要素モリモリでございます。

ビルドサーバーのVirtualMachineはAzure上にある。

でも、検証環境は自社の閉域ネットワーク内のどこそこにある。といった場合に。

(きわめてレアだとは思いますが!)

ちなみに使用するGatewayとか高めのお値段なので

自前の閉域環境内にサーバ用意できるのであればそちらのほうが良いと思います。

どちらかというとIaaSの環境をVPNで自社VPNに接続する手法がメインとなりますし

そちら単独のほうがよくあるパターンだとは思います。

CIは「いけんじゃね?」的なフィーリングの実験です。

下図な感じの構成で今回作ってみます。

f:id:TakasDev:20171104111618p:plain

参考資料

Point To Site

docs.microsoft.com

docs.microsoft.com

docs.microsoft.com

VSTSとJenkinsをつなげるときに参考

docs.microsoft.com

blog.nextscape.net

Jenkins

Windows Serverへのインストール

Azure準備

まずはAzure上の環境を構築します。

Azure上で作成したVM仮想環境から、閉域環境内(社内等)にVPN接続できる状態まで持っていきます

[Point To Site]という手法を使用します。

Point To Site構成の作成

仮想ネットワークのアドレス空間の追加

仮想ネットワークサブネットの作成

  • 上記で作成した仮想ネットワークアドレス空間を対象に設定します。
  • バックエンドのサブネットとゲートウェイサブネットを追加します。

    f:id:TakasDev:20171104103241p:plain

    f:id:TakasDev:20171104103310p:plain

仮想ネットワークゲートウェイの作成

  • 先ほど設定した仮想ネットワークをターゲットにゲートウェイを作成します。

    f:id:TakasDev:20171104103915p:plain

自己証明書を作成

  • WindowsServer2016以降の場合
    • PowerShellで[New-SelfSignedCertificate]実行が鉄板です。
  • MakeCer.exeを使用したい場合

  • できあがったルート証明書とクライアント証明書のCerとPfxをエクスポートします。

    • pfxはbase64形式でエクスポートします。

ゲートウェイの設定

  • アドレスプールとルート証明書を設定します。
  • アドレスプールはこれまで指定してきたものと別のIPアドレス空間を指定します
    • ([10.0.0.0/24]とか指定したら[10.1.0.0/24]みたいな感じですかね?)
  • 上記で作成した証明書をエディタかなにかで開き内部コードを編集します。
    • 改行コードが入っているので、改行部分をつぶします。

VirtualGatewayのセットアップ

  • 先程改行コードを潰したpfx内の文字列を設定します。
  • VPNクライアントをインストールします

接続設定の変更

※この作業が必要かどうかはちょっと微妙ですが

  • AzureVMクからライアント環境への参照はそのままでは行えないです。
  • インターネットオプション/Chromeの[設定]>[詳細詳細]>[プロキシ設定を開く]から[接続]の設定
  • 先ほど作成したVPNクライアントを選択し[設定]

f:id:TakasDev:20171104104608p:plain

  • 「設定を自動的に検出する」

接続の確認

作成したVPN内のIPアドレスは、コマンドプロンプトの[ipconfig]で確認することができます。

特に設定していないため、下図のIPアドレスVPNの接続の度変わります。

以降の図等でのIPアドレスの表記は、下図のものと異なる場合があります。

f:id:TakasDev:20171104104711p:plain

ネットワーク設定でリモート接続やファイル共有を

プライベートネットワーク内でできるようにしたうえで

AzureのVM上からVPN内の端末にアクセスできるか試してみます、

f:id:TakasDev:20171104104945p:plain

問題なく接続できるようです。

VSTSの設定

アカウント設定

Jenkinsからソースを抜けるように、VSTSの[authentication credentials]を設定します。

ユーザー名の[Security]>[authentication credentials]から設定可能です。

f:id:TakasDev:20171104105730p:plain

Jenkinsの設定

インストール

公式のドキュメントどおりにインストールします。

ビルド環境準備

  • Java SDK
    • Jenkins-CLI動かすのにJavaが必要なので
  • Git
    • Git管理用
    • [Use Git from the windows...]をチェックしといたほうが良いと思います。

以降必要があれば…

CI環境の設定

ひとまず今回はてっとりばやく、VSTSから取得したAngularをBuildした成果物を

VPN内の共有ディレクトリに突っ込む方法で検証してみます。

下記の感じでPowerShellスクリプトを実行します。

  1. npm i - Javascriptパッケージインストール
  2. ng build - JavascriptBuild
  3. Copy-Item - 成果物の移動

回してみる

AzureのVMから、Jenkinsを使ってVPN内のパスにDeployできるようになりました。

f:id:TakasDev:20171104112129g:plain

Azureハイブリッド接続でAzureWebAppsとオンプレミスのDBをつなげよう

AzureにWebAppsを置いてもいいけど他アプリケーションとの連携の関係で

SQLDatabaseはオンプレミスサーバーに置いときたい!なんて事が合った場合に。

ちと手順が複雑で日本語の最新資料も見当たらなかったのでメモ書き程度に。

参考文献

少し古いですが、AtoZ等は↓を

github.com

ハイブリッド接続に関しては↓を参考にしました。

docs.microsoft.com

準備

まずは、SQLServerを立てるオンプレミス環境とWebAppsを準備します。

自前の環境に直接つなげるのはあれなので

無償期間内で使用できるWindwosServerを使用しました。

www.microsoft.com

AzureのWebAppsは今回使用する「ハイブリッド接続」が

Basicからの対応となっているので、B1環境で構築しました。

(Basic環境はサポート対象外のようなので、実運用はStandardからですね!)

SQLServerの準備

SQLServerのExpress版をオンプレミスの仮想環境内に突っ込みます。

TCP通信できるようにしておきます。

詳細な手順については手順を説明しているサイトが多くあるのでそちらをご参考ください。

ServiceBusの構築

ハイブリッド接続で使用するAzure ServiceBusを構築します。

設定するものは名前ぐらいで、特別な設定等は行っていないので、詳細は省きます。

WebAppsでハイブリッド接続の設定

WebAppsの「ネットワーク」>「ハイブリッド接続」>「ハイブリッドエンドポイントの構成」から

ハイブリッド接続の設定画面に行くことが出来ます。

f:id:TakasDev:20171014230502p:plain

「ハイブリッド接続の追加」> 「ハイブリッド接続の新規作成」から

ハイブリッド接続設定を追加できます。

f:id:TakasDev:20171014230546p:plain

  • ハイブリッド接続の名前
    • 適当にそれっぽい名前をつけました。
  • エンドポイントホスト
    • エンドポイントのホスト名(オンプレミスサーバーの名)を付けました。
  • エンドポイントポート
    • SQLServerの標準のTCPポートの1433を使用しました。
  • サービスバス
    • 既存で先ほど作成したサービスバスを使用するようにしました。

オンプレミス環境からの接続

ハイブリッド接続設定画面の「接続マネージャダウンロード」で

クライアントソフトウェアをダウンロードします。

インストーラはオンプレミスDBが存在するサーバ上で実行します。

f:id:TakasDev:20171014230636p:plain

インストールしたソフトウェア「Hybrid Connection Manager UI」を起動すると

Azureにログインするためにログイン画面がたちあがあります。

先ほどハイブリッド接続の設定を行ったアカウントでログインします。

f:id:TakasDev:20171014230700p:plain

「Configure another Hybrid Connection」でハイブリッド接続の接続設定を行います

f:id:TakasDev:20171014230722p:plain

Subscripyionでハイブリッド接続の設定を作成したサブスクリプションを選択すると

サブスクリプションに紐づくハイブリッド接続の一覧が表示されます。

その中から使用する接続設定を選択し、[save]で決定します。

Connectedになったら接続設定完了です。

f:id:TakasDev:20171014230700p:plain

WebAppsとDBの接続確認

まずはローカル環境でDBに接続できるWebAppをサクッと作成します。

VS2017のテンプレートだと、ASP.netMVCのSPAテンプレートが

確認しやすいと思います。

web.configの接続文字列を書き換えるだけでOKなので。

f:id:TakasDev:20171014230819p:plain

f:id:TakasDev:20171014230851p:plain

ひとまず、Localでの実行で「devtakas@devtakas.com」でユーザーを作成してみました。

発行

いつもの手順でハイブリッド接続の設定を行ったWebAppsに発行を行います。

発行されたWebAppsに「「devtakas@devtakas.com」」でログインしてみます。

ログイン失敗!

ログインしようとするとエラーが発生してしまいました。

SQLServerの名前付インスタンスは動的ポートとしてUDPをしようするそうですが

これはハイブリッド接続ではサポートされないそうです。

なので、SQLServerの名前付きインスタンスの構成を変更します。

SQLServerのネットワーク構成の変更

SQLServer構成マネージャ」プログラムから

今回対応する名前付きインスタンスのネットワークプロトコル構成を選択します。

f:id:TakasDev:20171014230919p:plain

TCP/IPのプロパティで「IPアドレス」タブを選択し、参考資料に合った通り

IPAIIのTCPPortを、上記エンドポイントで指定した1433ポートを指定しました。

f:id:TakasDev:20171014230947p:plain

変更後、ホスト名のみでDB接続できるようになっていればOKです。

成功!

f:id:TakasDev:20171014231050p:plain

オンプレで登録したユーザー情報でログインできました!

Angular Materialを自分好みのカラーパレットに変更する

はじめに

下記バージョン構成でお送りします。

Angular : 4.4.4

Angular-cli : 1.4.3

Angular Material:2.0.0-beta.12

Angular Material

Angular Material

まだβなんですが、主たるコントロールはそろっているので

angularでマテリアルデザインのサイトを作りたいときは

非常に重宝するかと思います。

ただ、現在のテンプレートのカラーパレットって↓みたいな感じのものしかないんですね

f:id:TakasDev:20171008093056p:plain

自分は紫好きなんでいいんですが

ここも自分で自由に変更出来たらモックサイト作るときに便利なので

自分好みの色で、Angular Materialを構成してみましょう。

まずはテンプレートのカラーパレットのCSSをみてみる

まずはGitHubCSSがどのような構成で作成されているのかみてみます。

github.com

deeppurple-amberのSCSSをみてみます。

$mat-deep-purpleにカラーパレットの設定が記述されてそうです。

では、$mat-deeppurpleを見てみます。

material2/_palette.scss at master · angular/material2 · GitHub

ここにはテーマのすべての設定が記述されているようなので、一部抜粋します。

$mat-deep-purple: (
  50: #ede7f6,
  100: #d1c4e9,
  200: #b39ddb,
  300: #9575cd,
  400: #7e57c2,
  500: #673ab7,
  600: #5e35b1,
  700: #512da8,
  800: #4527a0,
  900: #311b92,
  A100: #b388ff,
  A200: #7c4dff,
  A400: #651fff,
  A700: #6200ea,
  contrast: (
    50: $black-87-opacity,
    100: $black-87-opacity,
    200: $black-87-opacity,
    300: white,
    400: white,
    500: $white-87-opacity,
    600: $white-87-opacity,
    700: $white-87-opacity,
    800: $white-87-opacity,
    900: $white-87-opacity,
    A100: $black-87-opacity,
    A200: white,
    A400: $white-87-opacity,
    A700: $white-87-opacity,
  )
);

色はこのように指定されているようです。

この構成は、Googleが提供している

マテリアルデザインのカラーパレットと同じ構成になっています。

(同じGoogle提供なんだから当然といえば当然ですよね)

Color - Style - Material Design

これと同じ構成で好きな色

または、上記のサイトのカラーパレットそのまま使って

SCSSを作ってあげれば

自分好みの色のテーマのマテリアルデザインのサイトが作れそうです。

カラーパレットを作る

しかし、色彩の専門家でもないですし、マテリアルデザインの色の勉強もしてないので

これを好きな色から自分で考えて組むのは骨が折れそうです。

なので、ジェネレータを使用して、カラーパレットを作成しちゃいます。

mcg.mbitson.com

適当にこんな感じの色にしてみました。

f:id:TakasDev:20171008095516p:plain

Angular MaterialのカラーパレットのSCSSの形でOutputできるので非常に楽です。

Angular Materialを組み込む

deep-purpleのSCSSと同じようにSCSSを作成してみます。

@import '~@angular/material/theming';
@include mat-core();

$mat-custom: (
    50 : #fef9e8,
    100 : #fcf0c6,
    200 : #fae7a1,
    300 : #f7dd7b,
    400 : #f6d55e,
    500 : #f4ce42,
    600 : #f3c93c,
    700 : #f1c233,
    800 : #efbc2b,
    900 : #ecb01d,
    A100 : #ffffff,
    A200 : #fffaee,
    A400 : #ffeabb,
    A700 : #ffe2a1,
    contrast: (
        50 : #000000,
        100 : #000000,
        200 : #000000,
        300 : #000000,
        400 : #000000,
        500 : #000000,
        600 : #000000,
        700 : #000000,
        800 : #000000,
        900 : #000000,
        A100 : #000000,
        A200 : #000000,
        A400 : #000000,
        A700 : #000000,
    )
);


$cust-app-primary: mat-palette($mat-custom);
$cust-app-accent:  mat-palette($mat-pink, A200, A100, A400);
$cust-app-warn:    mat-palette($mat-red);

$cust-app-theme: mat-light-theme($cust-app-primary, $cust-app-accent, $cust-app-warn);

@include angular-material-theme($cust-app-theme);

SCSSはangular-cli.jsonのStylesで読み込ませると、ビルド時にCSSにしてくれるので

angular-cli.jsonで上記のSCSSをStylesに食わせるだけでOKです。

結果

わかりやすそうなComponentだけピックアップして表示してみました。

f:id:TakasDev:20171008122542p:plain

Primaryボタンが一番わかりやすいですが

問題なくOriginalのカラーパレットが使用されているようです。

XamarinでUtf8Jsonを使おうとしてドはまりした話

最強Jsonリアライザと噂のUtf8JsonをXamarinで使用しようとしてドはまりした話です。

公式のGithubは↓です。使用の仕方からすごくわかりやすく記述されています!

github.com

neue cc - Utf8Json - C#最速のJSONシリアライザ(for .NET Standard 2.0, Unity)

はまった原因としては。。。うん。まぁ環境構築やらで自分のやり方が悪いだけな気がします。。。

新規プロジェクトの作成から

f:id:TakasDev:20171007232510p:plain

f:id:TakasDev:20171007233304p:plain

ひとまずUtf8JSonは.netframework4.5からってことのようなので

.netframework4.5.2、Xamarin.Forms + PCLの上図みたいな構成で

新規にプロジェクトを作ってみました。

Utf8Jsonは公式GithubのREADMEどおりに、NuGetからパッケージインストールしてみます。

f:id:TakasDev:20171007234129p:plain

あーはん?

f:id:TakasDev:20171007234535p:plain

んー。Dependencyの子たちをInstallしてみようとしてもうまくいかない。。

.netframeworkのPCLのプロファイル構成を111とかに変更したり

.netframework4.5.2ではなく、4.5で新規にプロジェクトを作り直したり

VisualStudio for macで作ったりしてもダメだったので

.netstandard2.0のPCLにする方法で手を打ってみます。

.netstandard2.0のPCL構成に変更

とおもったけどデフォルトで.netstandard2.0なPCLの構成はつくれないのかな?

nuitsさんのこちらの記事を参考に、.netstandardなPCLを作成してみました。

www.nuits.jp

f:id:TakasDev:20171008005522p:plain

上記の通り.netstandard、PCLライブラリもできて

エミュレータ上で実行確認できたので、本命のUtf8JsonをInstallしてみます!

f:id:TakasDev:20171008005835p:plain

うひょー!

Utf8Jsonうごくかためしてみる

Utf8Jsonの依存先のCLが、内部を実装してないと意味がないので動作するか試してみます。

確認につかったソースは公式のGithubのREADMEそのまんまです。

f:id:TakasDev:20171008011154p:plain

いぇあ!うごきました!

今回、XamarinFormsのプロジェクトに直接突っ込もうとしてドはまりしたわけだけど

実際の運用を考えるとUtf8Jsonを使用するような処理を切り出して

.netstandardのプロジェクトを別個作成することにはなると思う。

エンプラ脳で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