2019.10.25
Vueでカクテルデータベースをリファインする話#15【vue-routerでオブジェクトを渡したい】
極楽だったサーバーサイドのコーディングはもう終わってしまった・・・・・・ふたたびフロントエンドです・・・・・・。いやだ・・・・・・。
コントローラー部分なんてこれだけですからね・・・・・・(笑)
APIリソースが定義されてるので、それをきれいに使いまわしすればおけおけおっけーって感じです。あとはSQLでカクテルのデータを取ってこればいいだけです。そのへんはファクトリーに丸投げするんですけどね。
ここで大きな問題となるのは
vue-routerでpostパラメータはどのような扱いになるのか?という話ですね。
URLパラメータとして付与することはできるんですが、URLを変えずに、というか
オブジェクトを渡して、その結果でビューを描写ってのが果たしてできるんですかね、っていうのをやりたいわけです。
このコンポーネントでしか使わないようなデータをVuexに持つ意味がわかりませんからね。
で、これも結構苦戦したんですけど、うまく行ったのでその全貌を公開します。
exeSearch:function(){
//検索の実行
if(this.validateObj.fails()){alert("入力項目に誤りがあります");return}
//必要項目は揃っているので、検索開始
cocktailSearchClass.setCategories(this.checkedCategories)
cocktailSearchClass.setSearchMethod(this.searchMethod)
cocktailSearchClass.setEasily(this.easily)
cocktailSearchClass.setMiddles(this.checkedMiddles)
cocktailSearchClass.setMethods(this.checkedMethods)
axios.post(process.env.MIX_SENTRY_DSN_PUBLIC+'/api/cocktailSearch', cocktailSearchClass.getObj())
.then( (response) =>{
this.$emit('closeForm');
this.$router.push({ name: 'SearchCocktailResult', params: { response } });
})
.catch(function (error) {
//なにかエラーが出た
console.log(error);
})
}
axios部分はこんな感じの実装になってます。ストアにいろいろセットして、それをオブジェクトにしてapiに投げてる感じですね。バリデーションが1行でわかりやすく済ませられるのはいいですねまじで。
で、ここでハマったんですけど、ふつうにthenを書くとthisがaxiosのスコープ内に入っちゃって参照できなくなるんですよね。なのでアロー演算子でスコープを変えて、thisがvueインスタンスを参照したままにすることで、いつも通りのthisのスコープを維持できるようになりました。
このthisのスコープ問題、結構上級者向けの話なんですけど、アロー演算子っていうか、ラムダ式っていうんですかね。僕もやっとこれに慣れてきたなあ、って感じです。
で、そのあとはそれぞれ別の処理なのでわけて説明します。まずはルーティングの方ですね。
{
path: 'result/Cocktails',
name: 'SearchCocktailResult',
component: SearchCocktailResult,
props: (route) => ({
...route.params
})
}
ルーティングですね。肝になってるのはpropsの部分に関数が入ってることです。
Functionモードっていうらしいんですけど、これが正直
ちょっとよくわからないんで、オブジェクトを渡したい時はとりあえずこうする・・・・・・って認識でいいのかな。普通のパラメータとして考えると文字列しか渡せないはずなんですが、いろいろぶっこんで渡したい時はpropにアクセスするとオブジェクトが返ってくるようなものを定義する・・・・・・みたいな???
で、実際にparamsの値にはroute.paramsで取得できるので、それを...で展開してるって感じですね。これ名前なんていうんだっけ。まあいいや。(笑)
mounted: function(){
console.log(this.$route.params)
},
取得に関してはこれでいいです。あとはコンポーネントの方で好きに調理してくれって感じですね。このままだとresponseを参照してて扱いにくいので、自分で送ったresultオブジェクトだけをやりとりする形に書き換える予定ではあります。
次はemitのほうですね。これ何がしたいかって、
モーダルダイアログを閉じたいんですよ。
具体的な原理はちょっとちゃんと理解はしてないんですけど、少なくともそれぞれのコンポーネントが独立して動いてる、つまりフォーム部分のコンポーネントが何かに差し替わったわけではないので、コンポーネントの再描写をしたところでダイアログボックスが消えるわけではない、って感じになってます。検索したら検索ボックスは閉じたいので、その処理をやりたいわけですね。
ただ、それを司ってるプロパティはこのform.vueの中にはないので、ダイアログボックスの開閉状況を管理している親コンポーネントにイベントを伝搬させなくてはなりません。なのでemitでイベントを送信します。
まぁこのへんの受け渡しというか仕組みに関してはググってくださいって感じです・・・・・・。
<template>
<v-dialog v-model="show">
<v-card>
<v-card-text>
<cocktailForm @closeForm="closeForm"></cocktailForm>
</v-card-text>
<v-card-actions>
<div class="flex-grow-1"></div>
<v-btn color="green darken-1" text @click.stop="show=false">Close</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import cocktailForm from '../Forms/Search/Cocktail/form.vue'
import {app} from "../../app"
export default {
components: {cocktailForm: cocktailForm},
props: {
value: Boolean
},
computed: {
show: {
get () {
return this.value
},
set (value) {
this.$emit('input', value)
}
}
},
methods:{
closeForm(){
this.show=false//closeFormイベントを受け取ったら、モーダルを閉じる
}
}
}
</script>
モーダルダイアログを司るvueファイルの全貌です。これ自体がモーダルダイアログで、共通パーツであるフォーム部分をボディに埋め込んでる、っていう感じの構成ですね。
cocktailFormコンポーネントからcloseFormが伝搬されてくるので、それを@で受け取ります。受け取りましたら、closeFormイベントを発火させたいって感じですね。名前が一緒だと分かりづらいかも知れませんけど(笑)
で、methods内のcloseForm()を呼び出します、と。closeボタンを押した時のイベントを参考に、showとかいう算出プロパティにfalseをセットすれば、またinputイベントがemitされていくわけですね。
これに関しては、こっから先の処理がなぜか追えないというか、確か
なんかわからんけど動くって状態っぽいのでスルーします(笑)(笑)
とりあえず、これであとはちょこちょこっといじれば検索部分は完成ですね。特に新しい機能を追加しようって感じではなければこっから先はわりと消化試合みあるんですが、せっかくなのでちょっと新しいシステムというか、前々から気になってたところを改修できないかと考えてみたいですね・・・・・・
っていう話を次回します。はい。