ember-bootstrapで、バリデーションを行う

- 環境
    - Ember.js 3.22
    - ember-bootstrap 4.4.0
    - ember-bootstrap-cp-validations 2.0.1
    - ember-cp-validations 4.0.0-beta.10
- ソースコード
    - https://github.com/mk2/ember-bootstrap-validation-demo

# Ember CP Validationsを使う

[Ember Bootstrapのアドオンページ](https://www.ember-bootstrap.com/addons)を見ると、いくつかのバリデーションライブラリが使えそうだなと一瞬思ってしまうのですが、最新のEmber Bootstrap (v4)と一緒に使えるのはおそらくember-bootstrap-cp-validationsだけです。

- ember-bootstrap-changeset-validations
    - ember-bootstrapのv3系だと動くようですが、v4だと動きません。
- ember-bootstrap-validations
    - Archiveされてるのでおそらく動かないでしょう。

# アドオンのインストール

```sh
ember install ember-bootstrap
ember install ember-bootstrap-cp-validations
ember install ember-cp-validations
```

# フォームを作る

まず、前提として、下記の2点を理解しておく必要があります。

- ember-bootstrap-cp-validations（ember-bootstrap）のFormコンポーネントは、Classicコンポーネントで作られている(`@ember/component`を継承している）
- ember-cp-validationsのバリデーションはMixinとして提供される

このため、最新のEmber.js Octanceエディションで使われる、Octaneコンポーネント（`@glimmer/compnent`を継承する）としてフォームを作ることは出来ません。注意してください。

なので、フォームコンポーネントは下記のコマンドで生成します。

```sh
ember g component -cc form-demo-01
```

これで、Classicコンポーネントのhbsファイルとjsファイルが生成されます。

# フォームの内容を書く

すべてのファイルの内容を書きます。

```hbs:app/components/form-demo-01.hbs
<BsForm @formLayout="vertical" @model={{this}} @onSubmit={{action "onSubmit"}} as |form|>
  <form.element @controlType="text" @label="ユーザー名" @placeholder="名前" @property="username" />
  <form.element
    @controlType="password"
    @label="パスワード"
    @placeholder="xxx"
    @property="password"
    @helpText="4文字以上"
  />
  <form.element
    @controlType="email"
    @label="メールアドレス"
    @placeholder="xxx@xxx.xxx"
    @property="email"
  />
  <form.element
    @controlType="email"
    @label="メールアドレスの確認"
    @placeholder="xxx@xxx.xxx"
    @property="emailConfirmation"
  />
  <form.submitButton>
    送信
  </form.submitButton>
</BsForm>
```

```js:app/components/form-demo-01.js
import Component from "@ember/component";
import { validator, buildValidations } from "ember-cp-validations";

const Validations = buildValidations({
  username: validator("presence", { presence: true, message: "必須フィールドです" }),
  password: [
    validator("presence", { presence: true, message: "必須フィールドです" }),
    validator("length", {
      min: 4,
      message: "4文字以上入力してください",
    }),
  ],
  email: [
    validator("presence", { presence: true, message: "必須フィールドです" }),
    validator("format", { type: "email", message: "Emailのフォーマットを入力してください" }),
  ],
  emailConfirmation: [
    validator("presence", { presence: true, message: "必須フィールドです" }),
    validator("confirmation", {
      on: "email",
      message: "Emailアドレスが合致しません",
      description: "Emailアドレスの確認",
    }),
  ],
});

export default Component.extend(Validations, {
  username: null,
  password: null,
  email: null,
  emailConfirmation: null,
  actions: {
    onSubmit() {
      console.log({
        username: this.username,
        password: this.password,
        email: this.email,
        emailConfirmation: this.emailConfirmation,
      });
    },
  },
});
```

コード自体は非常に読みやすいですね。`buildValidations`でバリデーションMixinを作成し、それをコンポーネントにMixinとして継承させていく、というスタイルになります。

Octanceコンポーネントとして作れるバリデーションライブラリがあると嬉しいのですが、そもそもまだember-bootstrapのフォームがClassicコンポーネントなので、なかなか難しそうです。