All the bills that you add are shown in the page through the BillsTable component.

We want it to be a table, and display the contents of the bills array that’s passed down from App. So here’s what we can do:

<template>
  <table class="table">
    <thead class="bg-blue-400 text-white">
      <tr>
        <th scope="col">Date</th>
        <th scope="col">Amount</th>
        <th scope="col">Category</th>
        <th scope="col"></th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(bill, index) in bills" :key="index" class="p-4">
        <td>{{bill.date}}</td>
        <td>${{bill.amount}}</td>
        <td>{{bill.category}}</td>
      </tr>
    </tbody>
  </table>
</template>

It’s a lot like we did to iterate on categories in the NavBar component: we use v-for to repeat the tr element for every bill.

Now the date is displayed in this format: 2018-01-30T15:08:26.118Z. This is machine-readable, not human readable. We can use the popular moment library, which has a set of ready-made Vue filters in vue-moment.

A filter allows us to format something at the time we want to display it.

This library has a nice example on its README:

<span>{{ someDate | moment("dddd, MMMM Do YYYY") }}</span>

See, we add | after a value, and we specify a function. In this case, the content of someDate will be processed by moment().

We add this library to the CodeSandbox dependencies, like you saw in the previous lesson for vuejs-datepicker (tip: search for vue moment brockpetrie to make that library show up), or locally you use npm:

npm install vue-moment

or with yarn:

yarn add vue-moment

To install this into Vue, we need to go in App.vue, add:

import Vue from 'vue'

before any import, and right after the list of imports, add:

Vue.use(require('vue-moment'))

Now in every component of the app, you can use those filters.

We’ll do this in BillsTable:

<tr v-for="(bill, index) in bills" :key="index" class="p-4">
  <td>{{bill.date | moment("MMM D YYYY")}}</td>
  <td>${{bill.amount}}</td>
  <td>{{bill.category}}</td>
</tr>

The MMM D YYYY string is the format of the date, and it means print the month name followed by the day number and the year.

Now let’s add something to the list: we want to add a small button that shows the AddBill component so we can add bills. I chose to make it part of the table, and span across an entire table row. Add it inside the tbody tag, before you iterate over the bills:

<tr>
  <td colspan="4">
    <button class="underline" @click="triggerShowAddBill">Add new</button>
  </td>
</tr>

triggerShowAddBill is a method we’re going to put in the component script:

<script>
  export default {
    name: 'BillsTable',
    props: ['bills'],
    methods: {
      triggerShowAddBill: function () {
        this.$emit('triggerShowAddBill')
      },
    },
  }
</script>

this method calls the parent (App.vue) triggerShowAddBill method, which sets the shouldShowAddBill state property to true:

triggerShowAddBill() {
  this.shouldShowAddBill = true
},

When this happens, the app shows the AddBill component, because that’s how we organized our App.vue template.

The other thing we need now is, we must pass bills and tell Vue to handle the triggerShowAddBill event:

<BillsTable :bills="bills" v-on:triggerShowAddBill="triggerShowAddBill" />

Notice that by passing bills in this way, the BillsTable component will automatically refresh its displayed output when we add a new bill.

And finally, we initialize shouldShowAddBill to false in the App state, to make sure the AddBill component does not show up unless it’s needed.

Now the app should show the bills, and if you click “Add bill”, you should see the AddBill component. You can add a new bill, and you should see the list again.

We add a little bit of styling to BillsTable, and we’re good to go:

<template>
  <table class="table">
    <thead class="bg-blue-400 text-white">
      <tr>
        <th scope="col">Date</th>
        <th scope="col">Amount</th>
        <th scope="col">Category</th>
        <th scope="col"></th>
      </tr>
    </thead>
    <tbody>
      <tr class="p-4 bg-blue-200 text-center">
        <td colspan="4">
          <button class="underline" @click="triggerShowAddBill">Add new</button>
        </td>
      </tr>
      <tr v-for="(bill, index) in bills" :key="index" class="p-4">
        <td>{{bill.date | moment("MMM D YYYY")}}</td>
        <td>${{bill.amount}}</td>
        <td>{{bill.category}}</td>
      </tr>
    </tbody>
  </table>
</template>

See the app in the current state on CodeSandbox.


Go to the next lesson