Vueでform送信前にデータを加工する方法

vue.jsでform送信前に値を更新する。

今回ですが、form送信前に値を加工する方法を書きます。

実は$nextTick()を使わないと失敗します。

ぎゅう

ご存知ないという方には、参考になると思います

目次

要件

今回の要件は下書き公開ボタンで、パロメータが異なる想定です。

publish_status0だと下書き保存1だと公開ボタンをクリックした想定にします。

actionを分ければいいなどあると思いますが、それもやろうと思えばできるやり方なので、ご安心ください。

準備

エンターキーでformを送信させない。

まずは、エンターキーを押すとformが送信されてしまう問題を解決します。

@submit.prevent="submit"を追加して、エンターキーによるform送信を防止します。

<template>
  <form :action="action" method="post" @submit.prevent="submit">
  </form>
</template>

さらに下書きボタンも追加します。

      <v-btn
        color="blue darken-1"
        text
        type="button"
        onclick="submit();"
      >
        下書き保存
      </v-btn>

<v-btn></v-btn>はvuetifyのボタンタグですが、なんでもいいです。

onclick="submit();"でformのsubmit()を実行させています。

ちなみにformのsubmit()はデフォルトであるので、定義していなくても使えます。

ひとまず、これでエンターキーによるformの送信を防ぎつつ、ボタンでsubmitできるようになりました。

publish_statusを追加

公開ステータスであるpublish_statusを追加します。

<input type="hidden" name="publish_status" v-model="publish_status">

上記のinputを設置します。

<template>
  <form :action="action" method="post" ref="form" @submit.prevent="submit">
    <input type="hidden" name="_token" :value="csrf" />
    <input type="hidden" name="publish_status" v-model="publish_status">
      <v-btn
        color="blue darken-1"
        text
        type="button"
        onclick="submit();"
      >
        下書き保存
      </v-btn>
  </form>
</template>
<script>
export default {
  props: {
    action: {
      type: String,
    },
  },
  data() {
    return {
      publish_status: 0,
      csrf: document
        .querySelector('meta[name="csrf-token"]')
        .getAttribute("content"),
    }
  },
}
</script>

これでpublish_statusを設置できました。

この値を操作していきたいと思います。

公開ボタンを設置する

続いて公開ボタンを設置したいと思います。

公開ボタンを押した際はpublish()を実行させたいと思います。

      <v-btn
        color="blue darken-1"
        text
        type="button"
        @click="publish();"
      >
        公開
      </v-btn>

早速、formに設置したいと思います

<template>
  <form :action="action" method="post" ref="form" @submit.prevent="submit">
    <input type="hidden" name="_token" :value="csrf" />
    <input type="hidden" name="publish_status" v-model="publish_status">
      <v-btn
        color="blue darken-1"
        text
        type="button"
        onclick="submit();"
      >
        下書き保存
      </v-btn>
      <v-btn
        color="blue darken-1"
        text
        type="button"
        @click="publish();"
      >
        公開
      </v-btn>
  </form>
</template>
<script>
export default {
  props: {
    action: {
      type: String,
    },
  },
  data() {
    return {
      publish_status: 0,
      csrf: document
        .querySelector('meta[name="csrf-token"]')
        .getAttribute("content"),
    }
  },
  methods: {
    publish() {
        // ここに公開処理を追加する。
    }
  },
}
</script>

今回本題のpublish()も用意しました。

これで準備が完了しました。

本題

さて、準備が終えたところで本題に入ります。

失敗パターン

  methods: {
    publish() {
      this.publish_status = 1; // 公開ステータスを更新
      return this.$refs.form.submit(); // ref="form"がついたformを送信
    }
  },

この処理で送信した場合、this.publish_status = 0で送信されます。

ぎゅう

でも「this.publish_status = 1;」で
値を更新してるじゃん

実は、メソッドがreturnされた後に値が更新されます

なので、メソッド内でどれだけ値を加工してsubmitしても更新されないです。

画面はしっかり表示が変わりますが、returnする前にsubmit()をしているので、値は元のままで送信しています。

ぎゅう

加工した意味ないじゃん…..

となると思います。

なので、returnした後にsubmitさせればいいのです

そこで登場するのが、$nextTick()です。

これはreturn後に次に実行するメソッドを定義することができます。

なので、$nextTick()内でsubmit()を書いてあげればいいのです。

成功パターン

  methods: {
    publish() {
      this.publish_status = 1; // 公開ステータスを更新 
      this.$nextTick(() => this.$refs.form.submit()); // return後に値が更新されるため、$nextTickでsubmit()

      return false;
    }
  },

これでreturnされた後にthis.$refs.form.submit()を実行されます。

returnされた後なので、this.publish_status = 1;でformが送信されます。

あとはサーバーサイド側でpublish_statusの値を参考に、公開処理をすれば完了です。

$nextTick

公式に書かれている情報を最後にみていきましょう!

nextTick
次の DOM 更新サイクルの後に実行するようにコールバックを遅延します。いくつかのデータを変更した直後に使って、DOM の更新を待ちます。

https://v3.ja.vuejs.org/api/global-api.html#nexttick
引数{Function} callback (optional)
使用方法次の DOM 更新サイクルの後に実行されるようコールバックを遅延します。なにかデータを変更したすぐ後に使って、DOM の更新を待ちます。これはコールバックの this コンテキストがこのメソッドを呼び出したインスタンスに自動的に束縛されることを除いて、グローバルの nextTick と同じです。
createApp({
  // ...
  methods: {
    // ...
    example() {
      // データの変更
      this.message = 'changed'
      // DOM はまだ更新されていない
      this.$nextTick(function() {
        // DOM が更新される
        // `this` は現在のインスタンスに束縛される
        this.doSomethingElse()
      })
    }
  }
})

終わりに

ということで、意外にもreturnされた後じゃないと、値が更新されないということでした。

正直、初めて知ったときは意外でした。

でも$nextTick()を使えば、値を加工した上でformを送信できるので、いろいろ応用できるでしょう。

今回は以上です。

ありがとうございました

ぎゅう
WEBエンジニア
渋谷でWEBエンジニアとして働く。
LaravelとVue.jsをよく取り扱い、誰でも仕様が伝わるコードを書くことを得意とする。
先輩だろうがプルリクにコメントをして、リファクタしまくる仕様伝わるコード書くマン
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次
閉じる