Laravelで掲示板を作成している途中だけれども、その素材をもとにVue.jsでオブジェクト指向フォームを作ってみるよ。
www.tohuandkonsome.site
オブジェクト指向フォームってなによ?と思われたあなた。自分もよくわからないんだ。
でも、おお!ってなったので振り返りながら書いていこうと思います。
教材は毎度お世話になっております、Laracastになります。
laracasts.com
準備
自分は、Laravelをサーバー側のアプリケーションとして用意しています。
そして、以下のような、「タイトル」と「本文」をサーバー側にpostするhtmlを用意しています。
(Laravelなので正確にはbladeだよ!)
create_ajax.blade.php(抜粋)
<div class="container justfy-center">
<form class="simple-form" action="/thread" method="post">
{{csrf_field()}}
<div class="simple-form__group">
<label class="simple-form__title" for="title">タイトル</label>
<input class="simple-form__input" type="text" name="title">
</div>
<div class="simple-form__group">
<label class="simple-form__title" for="title">本文</label>
<input class="simple-form__input" type="text" name="body">
</div>
<div class="simple-form__footer">
<button class="simple-form__submit-btn">Post</button>
</div>
</form>
</div>
このhtmlをブラウザでみてみると、こんな感じの画面になります。
続いては、肝心のVue.jsになります。
さきほどのhtml内の.simple-formをエレメントとしてVueインスタンスを作成しています。
app.js
const app = new Vue({
el: '.simple-form'
});
また、Laravelなのでrequire('vue')
してwebpackでコンパイルしていたりしますが、そのへんは割愛しているよ。
とりあえずAjaxでPostするようにしていくよ
なにはともあれ?とりあえずAjaxでサーバにpostしてみるよ!
まずは、フォームでボタンを押下したときに発生するデフォルトのイベントsubmit
をキャンセルして、Vueインスタンスのメソッドを呼ぶ様にしよう。
create_ajax.blade.php(抜粋)
<div class="container justfy-center">
<form class="simple-form" action="/thread" method="post" v-on:submit.prevent="onSubmit">
Vueインスタンス側には、試しにメソッドが呼べているかどうか確認するために、console.log()
で何かしらだしてみる。
app.js
const app = new Vue({
el: '.simple-form',
methods:{
onSubmit:function(){
console.log("submit!!!");
}
}
});
そうすると、こんな感じでボタンを押すたびに、ブラウザのコンソールに文字列が出力されるね!
これで、submitのイベントをVueインスタンスのメソッドonSubmit
に置き換えることができました。
onSubmit
をしたらフォームの入力データを取ってきて、リクエストデータをつくってサーバーにpostするんだな!ってなんとなく見えてきました。
フォームのデータをとってくる:v-model
では、さっそくフォームの入力データをとってきます。
入力データをjavascriptでとってくる場合、formにname属性をつけて、それをdocumentオブジェクトから見て〜みたいなことをしますよね!(今日知った。)
参考にさせていただいたサイト
ピュアな JavaScript でフォーム(form)系要素の値を取得, 設定する方法一覧 | phiary
Vue.jsの場合はv-modelを使って、データバインディングをしていきます。
v-modelを使う。
では、さっそくv-modelをつかってフォームバインディングをしていくよ!
html側はこんな感じにフォームのコントロール系のタグと、Vueインスタンスの変数をバインディングしてあげます。
create_ajax.blade.php
<div class="container justfy-center">
<form class="simple-form" action="/thread" method="post" v-on:submit.prevent="onSubmit">
{{csrf_field()}}
<div class="simple-form__group">
<label class="simple-form__title" for="title">タイトル</label>
<input class="simple-form__input" type="text" name="title" v-model="title">
</div>
<div class="simple-form__group">
<label class="simple-form__title" for="title" >本文</label>
<input class="simple-form__input" type="text" name="body" v-model="body">
</div>
<div class="simple-form__footer">
<button class="simple-form__submit-btn">Post</button>
</div>
</form>
</div>
一方のapp.js
には、バインドするデータをdata
配下に定義してあげます。
また、中身を確認するために、さきほどのonSubmit
メソッド内にバインドするデータを表示する処理を追加しておきます。
app.js
const app = new Vue({
el: '.simple-form',
data:{
title:'',
body:'',
},
methods:{
onSubmit:function(){
console.log('title='+ this.title);
console.log('body='+ this.body);
}
}
});
この状態で、ブラウザを開いて、フォームに値を入力してボタンを押してみましょう。
こんな感じで、コンソールに入力された内容が出力されると思うんだ!
イメージにするとこんな感じだね!
逆にVueインスタンスのdataの値を変更したら、その内容がブラウザに表示されるのかしら。
試しにやってみよう。
submit
を行う以外にもうひとつ確認用のボタンを追加すると、
create_ajax.blade.php(抜粋)
<div class="simple-form__footer">
<button button="button" class="simple-form__submit-btn" v-on:click="changeTitle">change!</button>
<button class="simple-form__submit-btn">Post</button>
</div>
ブラウザはこんな感じになって、
app.js
に値をかえるメソッドchangeTitle
を書いてあげます。
app.js
el: '.simple-form',
data:{
title:'',
body:'',
},
methods:{
onSubmit:function(){
console.log('title='+ this.title);
console.log('body='+ this.body);
},
changeTitle:function(){
this.title="change!"
}
}
});
これで、ブラウザで確認用のボタンを押すと、
こんな感じで、ブラウザ側の表示もちゃんとかわることがわかるね!
こちらもくどいですが、イメージにするとこんな感じですかね。
axiosを使ってサーバにpostする
フォームの入力データがバインディグで簡単に取得できることがわかったので、さっそくデータをサーバーにpostしてみよう。
純粋なjavascriptだとXMLHttpRequestオブジェクトを使って〜みたいなことをするかと思います。
ためになる記事
JavascriptのAjaxについての基本まとめ - Qiita
が、ここではより簡単にAjaxを利用できるaxiosを使っていきます。
axiosの導入自体は割愛しちゃうんだよ!
とりあえずだったらCDNを使っちゃえばいいからね!Laravelだと標準で用意されているよ!
こんな感じで、axios.post
で送信先のurlと送信するデータを書いていくよ。
ここでは固定の文字列hello
とpinky
を送ってるね。
app.js
el: '.simple-form',
data:{
title:'',
body:'',
},
methods:{
onSubmit:function(){
axios.post('/thread',{
title:'hello!',
body:'pinky!'
})
},
}
});
データバインディングしたデータを送るのであれば、`this.title'みたいに定義しちゃえばいいね!
app.js
el: '.simple-form',
data:{
title:'',
body:'',
},
methods:{
onSubmit:function(){
axios.post('/thread',{
title: this.title,
body: this.body
})
},
}
});
ええい、定義してあるものは全部送るんじゃ!というのであればthis.$dataってしとくと、dataで定義しているデータを全部送っちゃうよ。
恐ろしい子!
app.js
el: '.simple-form',
data:{
title:'',
body:'',
},
methods:{
onSubmit:function(){
axios.post('/thread', this.$data);
},
}
});
ちょっと横道に入る
データを送るっていってるけど、何を送ってるんだよ!と思った方がもしかしたらいるかもしれません。
Chromeをデペロッパーツールで開いて、Networkをみるとリクエストだったりレスポンスの中身が見れるから、ぜひ見てみよう!
簡単に抜粋すると、サーバーにはこんな感じでリクエストを送っているよ。
HTTPリクエストの中身
//HTTPリクエストヘッダーがあって
POST /thread HTTP/1.1
Host: homestead.app
Connection: keep-alive
Content-Length: 34
Pragma: no-cache
Cache-Control: no-cache
//(省略)
//ヘッダーに一行あけて、リクエストbodyの内容がセットされているね。
{"title":"hello!","body":"pinky!"}
本当に参考程度だったね!
レスポンスを受け取ろう
今、axiosでpostするぜ!って処理になってるんだけれども、リクエストを投げっぱなしで結果がわからないね、
なので、こんな感じにレスポンスを受け取ってあげよう。
app.js(抜粋)
onSubmit:function(){
axios.post('/thread', this.$data)
.then(response => console.log(response.data))
.catch(error => console.log(error.response));
},
ちなみにHTTPリクエストが失敗って、何をもって失敗なんだろうかという点だけれども、公式ドキュメントをさらっと読むと、デフォルトだとHTTPステータスコートが200番台のときは成功みたい(あってるかな?)
やばい!最後がなんか投げやりになってる、ちっとも話が進まない!というところで次回に回します。