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.