Laravel5.5こと始め 〜9. Vue.jsとAPIベースのユーザ管理アプリへのペジネーション追加〜


内容

以下の順番にまとめます。
1. MacへのXAMPP+Laravelインストール
2. ユーザログイン機能の追加
3. MVCとルーティングの説明
4. ユーザリストの表示
5. ユーザリストのペジネーション表示
6. ユーザ管理APIの追加
7. Vue.jsとAPIベースのユーザ管理アプリの追加準備
8. Vue.jsとAPIベースのユーザ管理アプリの追加
9. Vue.jsとAPIベースのユーザ管理アプリへのペジネーション追加 ←いまここ
10. APIへのJWTAuth認証の追加
11. Vue.jsとAPIベースのユーザ管理アプリへの認証の追加

9. Vue.jsとAPIベースのユーザ管理アプリへのペジネーション追加

9.1 laravel-vue-paginationのインストール

下記のコマンドを実行して、「laravel-vue-pagination」ライブラリをインストールします。

$ npm install --save-dev laravel-vue-pagination
+ [email protected]
added 1 package from 1 contributor and audited 18965 packages in 12.873s
found 11 moderate severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details

package.jsonファイルは下記の通りとなります。

{
    "private": true,
    "scripts": {
... (中略)
    },
    "devDependencies": {
        "ajv": "^6.5.2",
        "axios": "^0.18",
        "bootstrap": "^4.0.0",
        "cross-env": "^5.1",
        "jquery": "^3.2",
        "laravel-mix": "^2.0",
        "laravel-vue-pagination": "^1.2.0",
        "lodash": "^4.17.4",
        "popper.js": "^1.12",
        "vue": "^2.5.7",
        "vue-axios": "^2.1.2",
        "vue-router": "^3.0.1",
        "vuetable-2": "^1.7.5"
    }
}

9.2 APIをペジネーション用に修正

「app/Http/Controllers/UserController.php」で実装されているユーザ管理用のAPIですが、ユーザ情報のリスト表示部分にぺじネーションを適用しますので、indexメソッドを下記の通り修正します。if文部分は得られたユーザリストが空の場合は「Record Not Found」のエラーをJSONで返すようにしています。

app/Http/Controllers/UserController.php
...
    public function index() // ユーザ一覧を返します
    {
        $users = User::paginate(1);
        if($users->getCollection()->isEmpty()) {
          return response()->json(['error'=>'Record Not Found'],404);
        }
        return $users;
    }
...

「php artisan serve」を実行して、APIの変化を確認します。

修正前は、「Laravel5.5こと始め 〜6. ユーザ管理APIの追加〜」に記載したとおり下記の通りのレスポンスがかえります。

$ curl -X GET http://localhost:8000/api/users 2>/dev/null | jq
[
  {
    "id": 1,
    "name": "test1",
    "email": "[email protected]",
    "created_at": "2018-07-09 13:43:53",
    "updated_at": "2018-07-09 13:43:53"
  },
  {
    "id": 2,
    "name": "test2",
    "email": "[email protected]",
    "created_at": "2018-07-09 13:43:53",
    "updated_at": "2018-07-09 13:43:53"
  },
  {
    "id": 3,
    "name": "test3",
    "email": "[email protected]",
    "created_at": "2018-07-09 13:43:54",
    "updated_at": "2018-07-09 13:43:54"
  }
]

1行でペジネーションするよう修正した後は下記の通りになります。

$ curl -X GET http://localhost:8000/api/users 2>/dev/null | jq
{
  "current_page": 1,
  "data": [
    {
      "id": 1,
      "name": "test1",
      "email": "[email protected]",
      "created_at": "2018-07-09 13:43:53",
      "updated_at": "2018-07-09 13:43:53"
    }
  ],
  "first_page_url": "http://localhost:8000/api/users?page=1",
  "from": 1,
  "last_page": 3,
  "last_page_url": "http://localhost:8000/api/users?page=3",
  "next_page_url": "http://localhost:8000/api/users?page=2",
  "path": "http://localhost:8000/api/users",
  "per_page": 1,
  "prev_page_url": null,
  "to": 1,
  "total": 3
}

2ページ目はパラメータにpageをセットして実行します。

$ curl -X GET http://localhost:8000/api/users?page=2 2>/dev/null | jq
{
  "current_page": 2,
  "data": [
    {
      "id": 2,
      "name": "test02",
      "email": "[email protected]",
      "created_at": "2018-07-09 13:43:53",
      "updated_at": "2018-07-09 14:03:20"
    }
  ],
  "first_page_url": "http://localhost:8000/api/users?page=1",
  "from": 2,
  "last_page": 3,
  "last_page_url": "http://localhost:8000/api/users?page=3",
  "next_page_url": "http://localhost:8000/api/users?page=3",
  "path": "http://localhost:8000/api/users",
  "per_page": 1,
  "prev_page_url": "http://localhost:8000/api/users?page=1",
  "to": 2,
  "total": 3
}

存在しない100ページ目を表示しようとすると、「Record Not Found」と言われます。

$ curl -X GET http://localhost:8000/api/users?page=100 2>/dev/null | jq
{
  "error": "Record Not Found"
}

ここでペジネーション有無でデータ部分の構造がどう異なるか見てみましょう。
ペジネーションなしの場合は以下の通りで「[{(ここにデータが入る)},...]という構造を持ちます。

[
  {
    "id": 1,
    "name": "test1",
    "email": "[email protected]",
...
  },
...

]

ペジネーションありの場合は以下の通りで「{"current_page":1,"data":[{(ここにデータが入る)},...],...}]」という構造を持ち、なしの場合の構造がタイトル"data"配下に配置される形になっています。

{
  "current_page": 1,
  "data": [
    {
      "id": 1,
      "name": "test1",
      "email": "[email protected]",
...
    },
...
  ],
...
  "first_page_url": "http://localhost:8000/api/users?page=1",
  "from": 1,
  "last_page": 3,
  "last_page_url": "http://localhost:8000/api/users?page=3",
  "next_page_url": "http://localhost:8000/api/users?page=2",
  "path": "http://localhost:8000/api/users",
  "per_page": 1,
  "prev_page_url": null,
  "to": 1,
  "total": 3
}

そのため、「UsersIndex.vue」において、ペジネーションなしで「app.users = resp.data;」と表現したものが、「app.users = resp.data.data;」となります。また、

9.3 Vueの修正

1. UsersIndex.vueの修正

resources/assets/js/components/UsersIndex.vue
<template>
  <div>
    <div class="form-group">
      <router-link :to="{name: 'createUser'}" class="btn btn-success">Create new user</router-link>
    </div>
    <div class="panel panel-default">
      <div class="panel-body">
        <table class="table table-bordered table-striped">
        <thead>
          <tr>
            <th>Name</th>
            <th>Email</th>
            <th width="100">&nbsp;</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="user, index in users.data"> <!--修正-->
            <td>{{ user.name }}</td>
            <td>{{ user.email }}</td>
            <td>
              <router-link :to="{name:'editUser',params:{id:user.id}}" class="btn btn-xs btn-default">Edit</router-link>
              <a href="#" class="btn btn-xs btn-danger" v-on:click="deleteEntry(user.id, index)">Delete</a>
            </td>
          </tr>
        </tbody>
        </table>
        <pagination :data="users" @pagination-change-page="getResults"></pagination> <!--追加-->
      </div>
    </div>
  </div>
</template>

<script>
  import http from '../http.js'
  import pagination from 'laravel-vue-pagination'; // 追記
  export default {
    data: function () {
      return {
        users: {} // 修正
      }
    },
    // 追記ここから
    components: { 
      pagination
    },
    // 追記ここまで
    mounted() {
      this.getResults();
    },
    methods: {
      getResults(page=1) { // 修正
        var app = this;
        http.get('users?page='+page,resp=>{ // 修正
          app.users = resp.data;
        })
      },
      deleteEntry(id, index) {
        if (confirm("Do you really want to delete it?")) {
          var app = this;
          http.delete('users/'+id,app.$router.go(0))
        }
      }
    }
  }
</script>

2. 「npm run dev」コマンドの実行

$ npm run dev
 DONE  Compiled successfully in 5155ms                                                                                                           12:56:20

       Asset     Size  Chunks                    Chunk Names
  /js/app.js  1.46 MB       0  [emitted]  [big]  /js/app
/css/app.css   196 kB    0, 0  [emitted]         /js/app, /js/app

これにより、「public/js/app.js」が更新されます。

ユーザ管理アプリの起動

実装したユーザ管理アプリをテストします。いつものように「php artisan serve」を実行して開発用サービスを開始します。

1. 「http://localhost:8000/home2 」にアクセスし、ログインします。

http://localhost:8000/home2 にアクセスするとログインしていない場合ログイン画面が表示されますのでログインします。

2. ユーザリストが表示されます。

3. ユーザを作成します。

「Create new user」ボタンを押下して、ユーザ情報を入力して「Create」ボタンを押下します。

ユーザが追加されてリスト表示されます。

4. ユーザ情報を編集します。

リストから編集したい行の「Edit」を押下して表示される「Edit User」画面でユーザ情報を編集し、「Edit」ボタンを押下します。

確認ダイアログが表示されますので、OKボタンを押下します。

編集された結果を反映したユーザ情報がリストされます。

5. ユーザ情報を削除します。

リストから削除したいユーザのDeleteボタンを押下すると、確認ダイアログが表示されるのでOKボタンを押下します。

削除が反映されて一覧が表示されます。

以上、「9. Vue.jsとAPIベースのユーザ管理アプリへのペジネーション追加」が完了です。

次は、「10. APIへのJWTAuth認証の追加」です。