LoginSignup
10
12

More than 5 years have passed since last update.

Laravelのモデルデータをvue.jsを使って非同期にソートする

Last updated at Posted at 2018-06-10

はじめに

今回作成したいのは、いわゆる「ソート機能」です。

こんなやつ↓
tes4.gif

Vue.jsのフィルターを使ってもcheckedを維持する – カバの樹

vue.jsを使って非同期に処理をします。
データはDBから取得したデータ(今回はLaravelをつかって)を利用します。

(jQueryを使ってモデルに紐付いていないデータをソートする方法は、色々あったのですがvueとLaravelを組み合わせて、データベースのデータを追加で取得する方法が無かったので今回記事を書きました。)

実装

index.js
const API_GET_DATA = '/api/data/get/'; // ①

new Vue({
  data(){
    return {
      order: '',
      orderItems: [ // ②
        {name: 'おすすめ順', value: 'recommend'},
        {name: '費用安い順', value: 'lowinitial'},
        {name: '近い順', value: 'nearly'},
      ]
    }
  },
  watch: {
    /**
    * 一覧の初期値取得
    * 初期表示はオススメ順でソート
    */
    order() {
      axios.post(API_GET_DATA, {
        order: this.order // ③
      })
      .then(res => {
        this.$store.commit('setValue', res.data);
      });
    }
  }
}

①実際に取得するデータのコントローラーまでのルーティングを記載しておきます。

②vue側のdataで予め、orderに渡す情報を記載しておきます。下のsort.htmlで利用します。

③そして、laravel側のDataGetController.phpに対して、selectで選択した値を渡す為に、apiに対してリクエストを投げます。
今回、帰ってきた値はvueのstoreに保存するようにしています。

sort.html
<div class="facility__sort">
    <p class="facility__sortHeader">並び替え:</p>
    <div class="selectbox">
        <select v-model="order" class="selectbox__input">
            <option v-for="(item, index) in orderItems" :value="item.value">{{ item.name }}</option>
        </select><i class="selectbox__icon"></i>
    </div>
</div>

v-forで先程dataに記載したorderItemsを利用して、valueとラベルを表示させます。
それ以外はなんの変哲もないselectフォームになります。

DataGetController.php
/**
 * @param Request $request
 *
 * @return ApiResponse
*/
public function main(Request $request)
{
    $order_type = $request->input('order', 'recommend');

    $data = $this->main_service->getByOrder($order_type);
    return new ApiResponse(['data' => $data]);
}

DataGetController.phpでは、モデルを取得するメソッドを呼び出します
(各自設計が異なりそうなので、今回は詳細は省略します。)

リクエストで取得した$order_typeの中には、orderItemsで選択されたvalueが値に入っています。
(例: 'おすすめ順' -> value: 'recommend')

流れとしては、それぞれのモデル等で、以下のようなデータの紐づけを定義しておきます。
取得したorderItemsの値に応じて、ソートする際にどのようなカラムが必要になるのかを考え、
それぞれのカラムを定義します。

こちらをサービス等で取得し、あとはorderByなどに渡してあげれば、クエリが発行できるので、それで取得できた値をvue側にreturnすると完了です。

DataModels.php
const ORDER_CONDITIONS = [
  'recommend' => [ // おすすめ順
    'order' => null
  ],
  'lowinitial' => [ // 費用安い順
    'order' => [
      'initial_price_min' => 'ASC',
     ],
   ],
  'nearly' => [ // 近い順
    'order' => [
      'distance' => 'ASC',
     ],
   ],
];
service.php
/**
 * 引数で受け取ったorder_typeに応じてそれぞれのソートを呼び出す。
 *
 * @param $city_id
 * @param $per_page
 * @param $page
 * @param $order_type
 * @return mixed
 */
public function getByOrder($order_type)
{
  if (! isset(DataModel::ORDER_CONDITIONS[$order_type])) {
    $order_type = 'recommend'; 
   }

  $order_conditions = DataModel::ORDER_CONDITIONS[$order_type];

  return $this->data->getByOrderType($order_condition);
}

例えば、以下のようにDataModelに定義した、並び替え情報をもとに$order_condition

(近い順だとこんな感じのデータ)

'order' => [
  'distance' => 'ASC',
 ],

を取得できますので、これをorderBy($order_condition)としてあげると、distanceカラムでソートされます。
こんな感じで値が取得できますので、そちらをリターンしてあげると、vue側でstoreに保存というような一連の流れを作ることができました。

おわりに

いかがだったでしょうか。

意外と簡単に非同期で、ソート機能を実現できました。(私はめちゃめちゃ時間がかかりましたが:joy:
vueとwebアプリケーションフレームワークの融合はかゆいところに手が届く感じがして、大変重宝しております。

また、機能単位でvueとフレームワークの実装をご紹介できたらと思います。

10
12
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
12