6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Riot.js フォームの扱い

Last updated at Posted at 2020-10-26

Riot.js

Riotでのフォームの扱い方を紹介します。

DOM要素に直接アクセス

おそらく一番簡単でわかりやすい方法です。フォームがちょっとでも複雑になるとコードがカオスになりがちなので実務ではあまり使いません。
サッと簡単なフォームを作る時にはこれで十分ですね。

<app-form>
  <form onsubmit="{ handleSubmit }">
    <input type="email" name="email" placeholder="メールアドレス" />
    <input type="password" name="password" placeholder="パスワード" />
    <input type="checkbox" id="password_visible" onchange="{ handleCheckChange }">
    <label for="password_visible">パスワード表示</l1abel>
    <button>送信</button>
  </form>
  <script>
    export default {
      handleCheckChange(e) {
        this.$('[name=password]').type = e.target.checked ? 'text' : 'password'
      },

      handleSubmit(e) {
        e.preventDefault()
        const email = this.$('[name=email]').value
        const password = this.$('[name=password]').value
        console.log({ email, password })
      }
    }
  </script>
</app-form>

##form要素から値を取得

送信するだけのフォームならおすすめです。
DOMを検索しない分上の方法よりパフォーマンスはいいのですが、誤差ですね😅

<app-form>
  <form onsubmit="{ handleSubmit }">
    <input type="email" name="email" placeholder="メールアドレス" />
    <input type="password" name="password" placeholder="パスワード" />
    <button>送信</button>
  </form>
  <script>
    export default {
      handleSubmit(e) {
        e.preventDefault()
        const fields = e.target.elements
        const email = fields['email'].value
        const password = fields['password'].value
        console.log({ email, password })
      }
    }
  </script>
</app-form>

##stateにフォームの値を持つ

冗長だけど凝ったことをするならこれ一択ですね。
自分はフォームを作るとき大体あとから複雑になってくるので、最初から全部この方法で統一しています。

<app-form>
  <form onsubmit="{ handleSubmit }">
    <input type="email" name="email" placeholder="メールアドレス" oninput="{ handleEmail }" value="{ state.email }" />
    <input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handlePassword }" value="{ state.password }" />
    <input type="checkbox" id="password_visible" onchange="{ handleCheckChange }">
    <label for="password_visible">パスワード表示</l1abel>
      <button>送信</button>
  </form>
  <script>
    export default {
      state: {
        email: '',
        password: '',
        passwordType: 'password'
      },

      handleEmail(e) {
        this.state.email = e.target.value
        this.update()
      },

      handlePassword(e) {
        this.state.password = e.target.value
        this.update()
      },

      handleCheckChange(e) {
        this.state.passwordType = e.target.checked ? 'text' : 'password'
        this.update()
      },

      handleSubmit(e) {
        e.preventDefault()
        console.log(this.state)
      }
    }
  </script>
</app-form>

さすがにフィールドごとにイベントハンドラーhandle...を用意するのは冗長すぎるので、普段は一つのハンドラーで工夫しています。

-    <input type="email" name="email" placeholder="メールアドレス" oninput="{ handleEmail }" value="{ state.email }" />
-    <input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handlePassword }" value="{ state.password }" />
+    <input type="email" name="email" placeholder="メールアドレス" oninput="{ handleChange }" value="{ state.email }" />
+    <input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handleChange }" value="{ state.password }" />
...

-      handleEmail(e) {
-        this.state.email = e.target.value
-        this.update()
-      },
-      handlePassword(e) {
-        this.state.password = e.target.value
-        this.update()
-      },
+      handleChange(e) {
+        this.state[e.target.name] = e.target.value
+        this.update()
+      },

##その他

name属性がないフィールドも扱う

<awesome-color-picker value="" on-change="" />という感じのname属性のないカスタムなコンポーネントがある時 + なるべくhandleChange一つにまとめたい

<app-form>
  <form onsubmit="{ handleSubmit }">
    <awesome-color-picker on-change="{ color => handleChange('color', color) }" value="{ state.color }" />
    <input type="text" oninput="{ e => handleChange('text', e.target.value) }" value="{ state.text }" />
  </form>
  <script>
    export default {
      state: {
        text: '',
        color: '#ffffff'
      },

      handleChange(name, value) {
        this.state[name] = value
        this.update()
      },

      handleSubmit(e) {
        e.preventDefault()
        console.log(this.state)
      }
    }
  </script>
</app-form>

{ e => handleChange('text', e.target.value) } ← 好みの問題ですがこれが「なんか気持ち悪い...」なら

-    <awesome-color-picker on-change="{ color => handleChange('color', color) }" value="{ state.color }" />
-    <input type="text" oninput="{ e => handleChange('text', e.target.value) }" value="{ state.text }" />
+    <awesome-color-picker on-change="{ handleChange('color') }" value="{ state.color }" />
+    <input type="text" oninput="{ handleChange('text') }" value="{ state.text }" />
...

-      handleChange(name, value) {
-        this.state[name] = value
-        this.update()
-      },
+      handleChange(name) {
+        return e => {
+          this.state[name] = e.target ? e.target.value : e;
+          this.update();
+        }
+      },

こっちの方がすっきりする気がします。

フォームが複雑になってくるとイベントハンドラ一つでカバーできないときもあるので、無理に一つにまとめずに複数のイベントハンドラを使いましょう。自分は単純なものは上にあったようなhandleChangeを使い、それ以外のものは個別にイベントハンドラを作ります。

##最後に
質問などがあれば気軽にコメントしてください!(^^♪

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?