2019.9.27
Vueでカクテルデータベースをリファインする話#5【APIリソース】
やっとSPAの本領発揮みたいなことができますね。
いま、ここまで作り終えたところです。テキストフォームに文字を入力すると、入力終了から0.5秒後に、非同期通信でデータベースと通信し、その結果がストアに代入されたのをwatchして必要な情報を表示する、という機構です。
で、次に実装するのは、このストアに格納された結果を用いて
検索結果を表示するというところですね。
もう検索結果は取ってある、というかストアに格納しているので、APIを叩く必要はもうありません。っていうか、2回もDBにアクセスしないで済むようにわざわざVuexでストア作るっていう回りくどいことしたんで・・・・・・笑
ここで僕が勉強しなきゃいけないのは、ルーティングと、for文、
可能ならばペジネーションですね。
(↑ペジネーションはやんないことにしました笑)
ルーティングに関してはふんわり最初の方でやってますので、それをボタンにくっつければいいかなって思います。0件ヒットの場合はボタンを非アクティブ化したいんですけど、それはクラス制御で簡単にできると思います。
で、Vueにデータ渡してv-forとかだったと思うんですけどそういうので繰り返し処理をさせたいところです。
が、ここでもうちょっと要件定義を考えてみましょう
例えば、「あ」とかで検索すると3000件超のデータが拾えるわけですが、いきなりそれを表示させるのって結構おじゃまかなって思うんですよね。
で、どういう機構を考えるか、ですね。
クリック回数は少なければ少ないほうがいいので、可能ならば検索結果を一気にばーーーって表示させたいんですけど、カクテル、カテゴリ、ミドルカテゴリ、銘柄・・・・・・の順で表示させていくつもりなんですがそうなると、例えば「アップルバレル」っていう銘柄を検索したく「あ」って入力したら、3000件超のカクテルの下にデータが表示させるわけじゃないですか。
それは明らかにジャマなので、どうにかしたいところですね。
で、アコーディオンにすることも考えたんですけど、無条件でクリックが発生するのはうんちっちですね。
ということで方針としては
ページ上部に付随して動くアンカーっていうのが良さそうな気がします。ということでそれを実装するのを目標にやっていきましょう。
まずはページを表示させないと始まらないので、読み込むところから始めましょう。
で、まず障壁となる要素としては
クリックするボタンのあるコンポーネントと別のコンポーネントを書き換える必要があるってとこですね。
これは
ネストされたルートっていうのを参考にすれば良さそうですね。
っていうか前にやったよなこれ
このへんがアヤシイですね・・・・・・(笑)
<router-link :to="{name:'FromNameResult'}" class="btn btn-sm btn-info" v-bind:class="{'text-danger': hasError }">
<span class="tb-visible none"><span class="glyphicon glyphicon-search" aria-hidden="true"></span></span>
<span class="tb-hidden">{{ message }}</span></router-link>
とりあえずこれが正解みたいですね。
:toでフィールド指定するのがミソっぽい。もちろんルーティングに名前を付けるのを忘れずに。
これでメインビューの方の子router-viewに紐付けることができたので、検索結果を表示させていきましょう。
ストアに検索結果がある前提で呼び出されるはずなので、検索結果ゼロの場合は基本的に考慮しなくても良さそうですけど、ポップアップで検索する時は検索結果ゼロの場合もあるし、なるべくコンポーネントは共通化したいので構造はちゃんと考えましょう。
コンポーネントを共通化しようと考えると、まずポップアップ検索の場合、検索結果として表示されるのは
カクテルのみになります。仕様が変わんなかったら。
つまり、検索結果を表示させる母体となるコンポーネントの中に、カクテルの検索結果、カテゴリの検索結果・・・・・・といったように、それぞれでコンポーネントを分ける構成になりそうですね。
で、そのうえでv-forでテキトーにループを回せば良さそうですね。処理が重くなるようであればペジネーションを考えるって感じです。
で、ここで問題が発生したんですが、
withってそういえばJOINじゃないんでしたね。なのでJSONにするとリレーションが適切に取れません。たぶん、PHPでリレーション先のプロパティを取得する際に
動的プロパティで取得しようとしているところに関係あるんじゃないかな、って思います。
そのままだとどうしても取得できなさそうなので、方法を色々考えることになります。自力でJOINしてもいいんですが
あんまり良い予感はしないので、Eloquentの形のまま対応したいところです。
なんとなくヒントになりそうなエントリを見つけたので、これでなんとか頑張ってみたいですね。
で、そもそもこういう仕組みを
APIリソースというらしい。このページ読んだことないですね(笑)
そうそう、やりたいのはまさにこれ!(だと思う)
ただ、気になるのがリソースはルートかコントローラーから直接返される、ってとこですね。
確かにAPIなのでjsonを返すわけで、実際僕も配列をそのまま返してるのは事実です。
実際に返してるJSONはこんな感じの構造になってて、自分でちょっと整形しちゃってるんですよね。ばらばらにAPI呼ぶのもおかしい話ですし。それにしても見やすいコード書けてると思いません?これが成長です(笑)
これをAPIリソースとして定義させてもらえるのか問題ですね。できない場合は自力で走査メソッドを定義するか、最初からJOINして取得するかの選択を迫られそう。
まぁ、これを解決するには、コントローラーメソッドをネストすればいいって結論にはなりそうですけどね。帰ってきたjsonをデシリアライズして配列に戻し、またjsonにシリアライズして送信・・・・・・いやぁ、これも無駄にコストかかってると思うけどなぁ・・・・・・しょうがないのかなぁ。
これができるのならこれが正解っぽいですね。あとはリレーションを取ってくることができればおけおけ、って感じ。
ちなみにこれを書いてる時点ではそこでハマっています
公式ドキュメントが見づらいので
このように整理されてるとわかりやすいですね。
とりあえず、最終的な形としてはこうなるハズです。公式ドキュメントを読んでこれが答えだってわかるんですかね・・・・・・?ほんとよく理解できたなぁ・・・・・・。
こう書くとリレーション含めてデータを取ってこれるようになります。
リレーションに関してはこんな風に渡していってあげればいいです。で、また別のAPIリソースを入れ子状に読んであげれば、そのとおりの構造になって返ってくるはずです。Many to Manyでもたぶん以下同文って感じで実装していけばお望みのJSONは得られると思います。
日本語は読めませんけど、カテゴリーの英名が取れてるので動いてることはわかりますね。こんな感じでリレーション含めて結果を返せるようになるので、あとはこれをうまいこと欲しい情報だけ取って来れるようにすればAPIに関しては完成かなって感じです。
dataでラップしない方法もあるみたいですが、事故が怖いし別に無理に剥がさなくてもいいかなと思ったんで、一番外のdataラップに関しては現状無視、って感じですね。
さて、これでしばらくは必要なデータを書き並べる単純作業になりそうですね。変なとこでハマっちゃいましたけど、次こそVueでデータ表示するところに入りたいですね。