今回ですが、form送信前に値を加工する方法を書きます。
実は$nextTick()
を使わないと失敗します。
ご存知ないという方には、参考になると思います
要件
今回の要件は下書き・公開ボタンで、パロメータが異なる想定です。
publish_status
が0
だと下書き保存、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
https://v3.ja.vuejs.org/api/global-api.html#nexttick
次の DOM 更新サイクルの後に実行するようにコールバックを遅延します。いくつかのデータを変更した直後に使って、DOM の更新を待ちます。
引数 | {Function} callback (optional) |
使用方法 | 次の DOM 更新サイクルの後に実行されるようコールバックを遅延します。なにかデータを変更したすぐ後に使って、DOM の更新を待ちます。これはコールバックの this コンテキストがこのメソッドを呼び出したインスタンスに自動的に束縛されることを除いて、グローバルの nextTick と同じです。 |
createApp({
// ...
methods: {
// ...
example() {
// データの変更
this.message = 'changed'
// DOM はまだ更新されていない
this.$nextTick(function() {
// DOM が更新される
// `this` は現在のインスタンスに束縛される
this.doSomethingElse()
})
}
}
})
終わりに
ということで、意外にもreturnされた後じゃないと、値が更新されないということでした。
正直、初めて知ったときは意外でした。
でも$nextTick()を使えば、値を加工した上でformを送信できるので、いろいろ応用できるでしょう。
今回は以上です。
ありがとうございました
コメント