Let’s Build a Web App with Vue, Chart.js and an API Part II

Second part of building a webapp which interacts with the npm api and generate charts

In case you missed the first part, you can find it here. First of all, wow! Thanks for all the feedback and twitter messages! 💝 I never imagined to reach such a wide audience. But enough of that. Let’s get to work 💪.

⚡ Quickstart

So, we are building npm-stats.org. A small web application build with Vue.js, vue-chartjs and the npm API, to grab the download statistics of packages and generate charts based on them.

What we have done so far

A small recap of what we have build in Part 1:

✅ Create a vue.js application with vue-init

✅ Install dependencies and setup the vue-router

✅ Create a Line Chart component with vue-chartjs

✅ Make an API call to npm and render the daily downloads statistics of the last-month

This is quite a lot. In the end we had our app running. However there is always space for improvement!

What we will do today:

⚙ Add settings to change the start and end period

📆 Integrate an external datepicker component

📈 Mutate our data to add a yearly statistics chart

🔨 Refactor our methods and DRY out a bit so we can easily add more charts

⚙ Settings

Right now our default period is set to last-month but it would be awesome if we could set the startPeriod and endPeriod. This way we could inspect the statistics for a whole year or more.

For this purpose we need to add two additional input fields and data models. But for a better user experience we will pull in an external datepicker component. We don’t have to reinvent the wheel right? 👨‍🔬 And to format our date properly we will also pull in moment.js

Datepicker

📆 Install dependencies

yarn add vuejs-datepicker moment

Todos for our Start.vue:

Import the datepicker

Add two datepicker fields for the start and end period

Add two data models

// Start.vue



<template>



...



<datepicker placeholder="Start Date" v-model="periodStart" name="start-date"></datepicker>

<datepicker placeholder="Start Date" v-model="periodStart" name="start-date"></datepicker>



...



</template>



<script>

import axios from 'axios'

import Datepicker from 'vuejs-datepicker'

import LineChart from '@/components/LineChart'



export default {

components: {

LineChart,

Datepicker

},

data () {

return {

package: null,

packageName: '',

loaded: false,

downloads: [],

labels: [],

showError: false,

errorMessage: 'Please enter a package name',

periodStart: '',

periodEnd: new Date()

}

},



.....

}



</script>

We also removed our old period data model which was set to last-month . As the period will now be composed of periodStart and periodEnd . We also set the periodEnd to the current day. As most of the time you will only change the start date.

We need a format like this: 2017-04-18:2017-04-30 . However if we now select a date we get something like this: 2017-04-17T22:00:00.000Z . A Date() with the time attributes, which we don't need. This is a nice job for moment.js .

Computing the period

For this case we have computed properties which are a pleasure to work with. To keep things a bit cleaner, we will create three properties. A formatted startDate, a formatted endDate and the composed period.

computed: {

_endDate () {

return moment(this.periodEnd).format('YYYY-MM-DD')

},

_startDate () {

return moment(this.periodStart).format('YYYY-MM-DD')

},

period () {

return this.periodStart ?

`${this._startDate}:${this._endDate}` :

'last-month'

}

},

As we want to persist the default behaviour of fetching data of the last month if no start date is set, we add our condition to the period property.

And thats it! We don’t need to change our request, as we simply replaced the content of period which we are using in our request. You can check the code on github in this feature branch

📈 More charts

Well, the chart with the daily statistics is great. But we can generate more! We have all data we need for that. We will not transform and group our data, so we can pass it to another line chart for yearly statistics. And we will refactor a bit our code.

All this data

So, our data we get from the npm api looks like this:

data: [

{day: "2017-04-18", downloads: 16280},

{day: "2017-04-19", downloads: 14280},

{day: "2017-04-20", downloads: 17280}

]

But to pass it to our chart we need two arrays, one which the labels (day) and one with the data (downloads). For the daily statistics, it was pretty easy. As we could simply use map() to get the data and labels. However now we need to do more.

Format our day key to a year. For the labels, remove the duplicates so we have only the unique years Sum all the downloads in the same year.

☝ But first, it is a good time to refactor some bits of our code. We see that step 1 is to format our date to a year. And later if we want monthly statistics we need to format it to a month format and so on. So it is a good time to introduce a helper method and extract the logic from the Start.vue file.

So we create src/utils/dateFormatter.js which will help us to format our date.

import moment from 'moment'



export const dateToYear = date => moment(date).format('YYYY')

export const dateToMonth = date => moment(date).format('MMM YYYY')

export const dateToWeek = date => moment(date).format('GGGG-[W]WW')

export const dateToDay = date => moment(date).format('YYYY-MM-DD')

export const dateBeautify = date => moment(date).format('Do MMMM YYYY')

And in our Start.vue we can now remove the moment import and import our helper modules and replace the moment statements with them. (In our _startPeriod and _endPeriod . And we add a new computed property to which will replace the period in our chart container.