Nuxt.js、Firestore、axiosでデータの投稿日時表示、ソート機能実装

#この記事の概要

↓以前書いた記事で作った掲示板アプリの追加実装を行います。
[Nuxt.js、Firebase、axiosでパパッと掲示板！](https://qiita.com/higa08/items/b33fc013d26426dc042a)

**※※※**
**前回からの続きになっております**
**以下、適宜axiosメソッドに渡しているURLの`YOUR_PROJECT_ID`を自分のプロジェクトIDに置き換える必要があることに注意してください。** 
`YOUR_PROJECT_ID`のままだと以下のエラーが出ます。
![スクリーンショット 2020-11-24 20.39.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/dcdbd945-b0da-8c99-4eab-80c0be24e4c6.png)
***

追加するのは

**・投稿日時の表示**
**・投稿日時順にソート**

# 目標物
![demo](https://gyazo.com/053154556c67a21c965392df52324ca0/raw)

![demo](https://gyazo.com/2f2bcdca9a1cfbc098616de7f759e7ab/raw)

# 追加で導入するもの

・[moment](https://github.com/moment/moment) (時刻フォーマットの整形用)
・[lodash](https://lodash.com/) (ソート用)

# moment
```:ターミナル
$ npm install --save moment
```

```vuejs:pages/index.vue
<script>
import moment from 'moment';
```

#lodash

導入方法は以下参照ください。
[webpack プラグインを追加するには？](https://ja.nuxtjs.org/faq/webpack-plugins/)

```javascript:nuxt.config.js
import webpack from 'webpack'
export default {

  //・・・・・・省略

  // Build Configuration (https://go.nuxtjs.dev/config-build)
  build: {
    plugins: [
      new webpack.ProvidePlugin({
        _: 'lodash'
      })
    ]
  }
}
```

# 投稿日時の表示

送るデータに`created`を追加

```vuejs:pages/index.vue
<script>
//・・・・・・・・・・・省略
  methods: {
    submitPosts() {
      this.$axios
        .$post(
          'https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/posts',
          {
            fields: {
              name: {
                stringValue: this.name
              },
              comment: {
                stringValue: this.comment
              },
//------------↓ここから--------------
              created: {
                timestampValue: new Date()
              }
//------------↑ここまで--------------
            }
          }
        )
        .then(() => {
          this.name = '';
          this.comment = '';
          this.getPosts();
        });
//・・・・・・・・・・・省略
</script>
```

そして表示


```vuejs:pages/index.vue
<template>

      <p>名前：{{post.fields.name.stringValue}}</p>
      <br>
      <p>コメント：{{post.fields.comment.stringValue}}</p>
      <br>
<!-----↓ここから-------------------------------------------------------->
      <p>投稿日時：{{post.fields.created.timestampValue}}</p>
      <br>
<!-----↑ここまで-------------------------------------------------------->
    </div>
  </div>
</template>

```

今こんな感じです。

![スクリーンショット 2020-11-28 19.57.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/9f2cb93c-a2a7-5e5d-f018-7cceeae0d88a.png)

あまり見慣れないフォーマットなのでわかりやすく整形します。

***

`filter`を使ってフォーマットを整形してあげましょう。
さらにここで`moment`を使用しています。

```vuejs:pages/index.vue
<script>
//・・・・・・・・・・・省略
    getPosts() {
      this.$axios.$get(
        "https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/posts"
      )
      .then(res => {
        this.posts = res.documents;
      });
    }
  },
//------------↓ここから--------------
  filters: {
    dateFilter(date) {
      return moment(date).format('YYYY/MM/DD HH:mm:ss');
    }
  }
//------------↑ここまで--------------
};
</script>
```
```vuejs:pages/index.vue
<template>
<!-----省略-------------------------->

      <p>投稿日時：{{post.fields.created.timestampValue | dateFilter}}</p>

<!-----省略--------------------------->
</template>

```
***
こうなったらOKです。
![スクリーンショット 2020-11-28 20.08.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/95e40adb-fabb-f828-9930-4932761e014c.png)
***

# 投稿日時でソートさせる
現状はこんな感じです。
これをソートさせて行きます。

![スクリーンショット 2020-11-28 20.13.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/99a2c627-11d8-1441-9750-b52a0c8c9425.png)

**lodash**の`_.orderBy`関数を使います

第一引数にソートしたい配列もしくはオブジェクト。
第二引数に値を渡します。

```vuejs:pages/index.vue
<script>
//・・・・・・・・・・・省略
    getPosts() {
      this.$axios.$get(
        "https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/posts"
      )
      .then(res => {
//-----------------------↓ここ--------------
        this.posts = _.orderBy(res.documents, 'fields.created.timestampValue');
      });
    }
  },
  filters: {
    dateFilter(date) {
      return moment(date).format('YYYY/MM/DD HH:mm:ss');
    }
  }
};
</script>
```
![スクリーンショット 2020-11-28 20.17.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/e310b969-a13b-4630-705a-f63acbf605cc.png)
***

OKです。
最後に昇順、降順を切り替えられる様にします。

# 昇順、降順の切り替え

```vuejs:pages/index.vue
<template>
  <div>
    <h1>掲示板！</h1>
    <br>名前
    <div>
      <input type="text" v-model="name">
    </div>コメント
    <div>
      <textarea v-model="comment"></textarea>
    </div>
    <br>
    <button @click="submitPosts">投稿する</button>
    <br>
    <br>
    <h2>投稿一覧</h2>
<!-----↓ここから-------------------------------------------------------->
    <select v-model="selected" @change="getPosts">
      <option>新しい順</option>
      <option>古い順</option>
    </select>
<!-----↑ここまで-------------------------------------------------------->


<!-----省略-------------------------->


</template>

<script>
import moment from 'moment';
export default {
  data() {
    return {
      name: '',
      comment: '',
      posts: [],
//--------↓ここ--------------
      selected: '新しい順'
    };
  },


//・・・・・・・・・・・省略
</script>
```
まずプルダウンを用意します
「新しい順」←→「古い順」と切り替わるごとに`selected`にその値が入ります、
`selected`のデフォルトの値は「新しい順」としておきます。
さらに切り替わるごとに`getPosts`メソッドを呼びリストレンダリングをします。
***

```vuejs:pages/index.vue
<script>
//・・・・・・・・・・・省略
    getPosts() {
      console.log('getPost')
      this.$axios
        .$get(
          'https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/posts'
        )
        .then(res => {
          switch (this.selected) {
            case '新しい順':
              this.posts = _.orderBy(res.documents, 'fields.created.timestampValue');
              break;
            case '古い順':
              this.posts = _.orderBy(res.documents, 'fields.created.timestampValue', 'desc');
              break;
          }
        });
    }
  },
//・・・・・・・・・・・省略
</script>
```

`_.orderBy`の第三引数に`'desc'`を渡すことで降順になります。
switch文で`selected`の値が「新しい順」なら昇順、「古い順」なら降順とします。

※第三引数に`'asc'`を渡すことで昇順を指定することもできます。

# 完成！

```vuejs:pages/index.vue
<template>
  <div>
    <h1>掲示板！</h1>
    <br>名前
    <div>
      <input type="text" v-model="name">
    </div>コメント
    <div>
      <textarea v-model="comment"></textarea>
    </div>
    <br>
    <button @click="submitPosts">投稿する</button>
    <br>
    <br>
    <h2>投稿一覧</h2>
    <select v-model="selected" @change="getPosts">
      <option>新しい順</option>
      <option>古い順</option>
    </select>
    <br>
    <div v-for="post in posts" :key="post.id">
      <hr>
      <br>
      <p>名前：{{post.fields.name.stringValue}}</p>
      <br>
      <p>コメント：{{post.fields.comment.stringValue}}</p>
      <br>
      <p>投稿日時：{{post.fields.created.timestampValue | dateFilter}}</p>
      <br>
    </div>
  </div>
</template>

<script>
import moment from 'moment';
export default {
  data() {
    return {
      name: '',
      comment: '',
      posts: [],
      selected: '新しい順'
    };
  },
  created() {
    this.getPosts();
  },
  methods: {
    submitPosts() {
      this.$axios
        .$post(
          'https://firestore.googleapis.com/v1/projects/vue-test-df33d/databases/(default)/documents/posts',
          {
            fields: {
              name: {
                stringValue: this.name
              },
              comment: {
                stringValue: this.comment
              },
              created: {
                timestampValue: new Date()
              }
            }
          }
        )
        .then(() => {
          this.name = '';
          this.comment = '';
          this.getPosts();
        });
    },
    getPosts() {
      this.$axios
        .$get(
          'https://firestore.googleapis.com/v1/projects/vue-test-df33d/databases/(default)/documents/posts'
        )
        .then(res => {
          switch (this.selected) {
            case '新しい順':
              this.posts = _.orderBy(res.documents, 'fields.created.timestampValue');
              break;
            case '古い順':
              this.posts = _.orderBy(res.documents, 'fields.created.timestampValue', 'desc');
              break;
          }
        });
    }
  },
  filters: {
    dateFilter(date) {
      return moment(date).format('YYYY/MM/DD HH:mm:ss');
    }
  }
};
</script>
```

お疲れさまでした！
最終的に記事上部の**目標物**の様になっていればOKです。