All-inclusive Vue.js beginner tutorial — building a converter app

MZ
10 min readSep 9, 2018

--

The converter app which you will be building in this tutorial. Complete code available on GitHub : https://github.com/InfectoOne/Vue-Converter-Example-App

Let’s just get straight to the point, without philosophizing about Vue.js and making vague statements about its concepts, powers, scalability and blah blah blah. The fact is: you want to learn Vue.js now and you want to see it in action. Understanding the underlying philosophy of a development tool is a necessity for every wise software developer, but starting off by reading a bunch of theory doesn’t really ignite a fire of motivation. Obtaining some intuition beforehand does though. The idea of this article is to help beginners quickly grasp the basic Vue.js concepts “on-the-go” while building an actual app, while experienced developers may use it as a cheat-sheet or to revise their knowledge.

Objectives of this tutorial:

  • build a simple converter app
  • learn how to start a new project using vue-cli
  • provide a step-by-step explanation while minimizing relying on prerequired knowledge*
  • explain all basic vue concepts such as components, directives, computed properties, props and see how to use them in our converter app

*the only requirements for this tutorial would be the basics of HTML, CSS, Javascript and basic usage of the terminal

1. Initializing a new project

First of all, install Node.js on your device. Node.js is a server-side platform on which your app will run, but you don’t need to know much about it for this tutorial. What we actually need is NPM, which gets installed alongside Node.js. NPM is a package manager — in other words, a program for downloading and managing modules (module = basically, a bundle of code files, a fragment of software ). We will use NPM to install vue-cli, a command-line interface for scaffolding and managing Vue.js apps. Now, open up your terminal and proceed with the following instructions:

  • having installed Node.js, install vue-cli by running the following command: npm install -g @vue/cli
  • now, go the folder where you’d like to create your project and run the following command: vue create my-converter
  • for the sake of simplicity, choose the default preset

DAYUMN! You have just created the foundation for your app! And we’re just getting started…

Switch to the newly created folder in your terminal (cd vue-converter on Windows), run the command npm run serve and finally (don’t close the terminal), open http://localhost:8080/ in your favorite web browser. What you should see is the following:

The pre-generated stuff in your app. We will completely replace this with our own code later on.

Keep your browser open. We’re about to start coding, my friend!

2. Vue Components

Grab your favorite text editor (mine is Visual Studio Code) and open the folder of your newly created project. Check out the project strucutre.

Structure of your new project

The only relevant folder for this tutorial is the src folder and it’s generally the folder where you will be doing something 90% of the time. Notice the components folder and the files with the .vue extension. Those are Single-File-Components. Components are decoupled fragments of your app responsible for a single task. Every component may have its own variables, template, styling etc. In other words - components are the building bricks of your app. They are relatively isolated from each other, but Vue offers certain means of communication between them. There can be a hierarchy between them, too (one component may include some other).The philosophy behind it is divide and conquer — splitting your app into separate components enhances readability, maintanance and reusability.

The skeleton of every vue components consists of the following:

  • <template> : it’s where you write your HTML
  • <script> : where you write your javascript
  • <style> : where you write your CSS

That means, all three things are neatly bundled in a single .vue file. The starting point of your app is the App.vue component. It will include and display all the other components. Let’s delete everything inside of it except the <template>, <script> and <style> opening and closing tags.

Finally, we will start coding. A little hint before that : check out your browser again — the app has been updated (it’s blank) even though you didn’t refresh the page! DAYUMN! This happens thanks to something called hot-reloading.

3. Creating our components — navbar and converter

Take a look at the screenshot of our app (at the beginning of this article). In what logical components could we split up our app? It makes sense to have the following 3 components:

  • Navbar — a component for the vertical navigation bar, where the user can pick his desired physical quantity (length, time, temperature)
  • Converter — a component where the user can choose units and do the actual conversion
  • App.vue — this one we already have and it’s pretty much obligatory. This will be the “boss” component, containing and synchronising the other two.

Let’s start! In the components folder, create two files: Navbar.vue and Converter.vue and write the empty <template>, <script> and <style>tags inside them. We will start with coding the navbar.

3.1 Navbar.vue

Starting off with the <template> part: create a <div> element which will be the parent element wrapping all of the other elements. To be more exact, every <template> MUST have just one direct child element. Now create three <a> elements for length, time and temperature:

Moving on to the script tag to write some javascript. Write this inside the script tag:

data() is a function which returns a plain javascript object where you declare your component’s variables. We have declared len, temp, time . Replace the hardcoded text in the <a> elements with the respective variables: replace <a>Length</a> with <a>{{len}}</a> and so on. Your template-tag should now look like this:

<template>         
<div id="nav">
<a> {{len}} </a>
<a> {{temp}} </a>
<a> {{time}} </a>
</div>
</template>

Take a look at your app in the browser: at first it seems as if nothing changed at all. You might wonder what advantage we got from doing. The crucial difference is, that the text values Length, Time and Temperature are not statically displayed anymore. They are dynamic — if we were to change the value of len e.g. by triggering some function, the displayed text would be updated immediately! That’s called data binding or interpolation and that syntax with the curly braces is called “Mustache” syntax. DAYUMN!

Now we will make the code even more elegant: instead of having three separate<a> tags, let’s declare an array of physical quantities and dynamically display <a> tags accordingly. Inside data(), create an array called quantities. Also, we won’t directly use strings like “Length”. Instead, the array will contain objects. An object will represent a physical quantity and contain its name and units. The name will be the actual string which we will display. Proceed with making those changes. data() should now look like this:

data(){
return{
quantities: [
{name:"Length", units:["mm","cm","m"]},
{name:"Temperature", units:["C","K","F"]}, {name:"Time", units:["s","min","h"]} ]
}
},

How are we going to display these? Of course, we could make three separate <a> tags again, but there is a more elegant generic solution. Remove those three <a> tags and replace them with the following:

<a v-for="quantity in quantities" 
v-bind:key="quantity.name"
@click="$emit('select-quantity',quantity)" >
{{quantity.name}}</a>

What’s new? The v-for you see is called a directive. Directives are something like vue-specific attributes of HTML elements. Our v-for iterates the quantities array and generates an <a> tag for every element inside the array , displaying its name attribute : {{quantity.name}}

The elements need to be uniquely identifiable. That’s what v-bind:keyis for.

What about @click="$emit('select-quantity', quantity)"? Obviously, when the user clicks on e.g. Length, we need to let the other components know what the user has clicked on. We will do that using custom events — one of the basic means of communication between vue components. Here in our case: when the user clicks on one of the <a> tags, we emit a custom event which we named 'select-quantity' and pass the corresponding physical quantity object. That event will be caught and reacted to in the App.vue component later on. But for now, spice the Navbar.vue component up with some CSS and you’re done.

Full code of the Navbar.vue component can be found HERE.

App.vue

We have created the Navbar.vue component. Now we will import it to App.vue and actually display it. We will also import and display the yet-to-be-implemented Converter.vue component. Also, App.vue will contain a variable called chosenQuantity which will represent the currently chosen physical quantity. That variable should change every time the user clicks a different button in the navbar — that means, every time the previously created custom event 'select-quantity' is emitted by the Navbar.vue component. Here’s how the code for all of that looks like:

3.2 Converter.vue

Before we move on to the last component, take a look at App.vue again. In Navbar.vue we click on an <a> tag and that click changes the chosenQuantity variable in App.vue. Now we need to pass that variable from App.vue to Converter.vue . This line does the job:

<Converter v-bind:physicalQuantity="chosenQuantity"/>

In that line, we have added the Converter.vue component to our app and passed it the variable physicalQuantity. This is something called props. We pass the chosenQuantityvariable to a props variable called physicalQuantity(yet to be defined in Converter.vue) from the parent to the child component. That’s the basic mechanism of parent-child communication. The other way around (child parent) is done using custom events, and we have already seen an example of that when we were emitting that 'select-quantity' event from Navbar.vue to App.vue. Moving on to Converter.vue:

Alrighty, we have now sucessfully passed the currently chosen quantity to Converter.vue and recieved it as a props called physicalQuantity . The expected type of physicalQuantity is Object because, if you recall, in Navbar.vue we represented a physical quantity as a javascript object, containing the name and its units.

What else is new? We have declared the variables fromValue, fromUnit, resultUnit which respectively stand for the value, the unit we are converting FROM and the unit we are converting TO.

Display name of currently selected physical quantity

We want to display the name of the currently selected physical quantity. We can do that using a <h1> element and interpolation :

<h1> {{physicalQuantity.name}} </h1>

Value to be converted

We want to create an input box, where the user can type in the desired value. This will determine the value of the fromValue variable. We can do that using the v-model directive, which will bind the fromValue variable to whatever the user types in and update its value accordingly:

<input type="text" v-model="fromValue">

Choosing between units

We want to create drop-down menus for picking the from-unit and the to-unit. When the user selects a unit, we need to bind the selection to the fromUnit variable in the first case or resultUnit in the second case. For that, we will create a basic HTML <select> element and using the v-for directive, we will generate possible selection options (<option> elements ) from the units array from physicalQuantity:

<-- UNIT TO CONVERT FORM -->
<select v-model="fromUnit">
<option v-for="unit in physicalQuantity.units" v-bind:key="unit"> {{unit}}
</option>
</select>
<-- UNIT TO CONVERT TO -->
<select v-model="resultUnit">
<option v-for="unit in physicalQuantity.units" v-bind:key="unit"> {{unit}}
</option>
</select>

Display the result

Now, let’s implement the actual logic for the computation of the result. In order to reduce logic complexity, I have decided on the following: For each physical quantity, let there be an “intermediary” unit. All values will be converted to that intermediary unit and then converted from the intermediary unit to the desired result unit. For example, if our intermediary unit for time is minutes(min), then, when converting seconds to hours, we convert seconds to minutes, then minutes to hours. This applies to every other possible case as well.

Right after data(), declare the functions (methods) for converting to intermediary units in our Converter.vue component:

And finally, we are going to calculate the actual result. Let’s store the result in a variable called result. Notice that this isn’t an ordinary value — it’s a value which depends on other values. In our case, result depends on the fromValue the user types in, the chosen fromUnit and resultUnit. In other words, result is a variable which will be the result of a computation. That’s why we will declare result as a computed property and we will implement the logic for the computation right away:

Looking good! Whenever one of the dependency values (e.g. fromValue) changes, the value of result will be updated accordingly right away! The only thing that remains is to actually display result in our template-part of the component. Let’s put it between the <select> elements:

<p id="result">
{{result}}
</p>

Spice it all up with some nice CSS (which you can check out HERE in the whole Converter.vue file) and you have finally successfully implemented your own Vue.js converter app! DAYUMN!

Objective (hopefully) accomplished!

Thank you for taking the time to read this tutorial. My objective was to fill a gap in teh interwebz by publishing a straightforward hands-on Vue.js tutorial and provide an explanation of some basic Vue concepts in a straightforward manner. The idea of this article was to give you a quick and efficient head start — for advanced Vue.js concepts and more in-detail explanations, the official documentation would definetly be the best learning source!

If you feel like this tutorial has helped you, I will appreciate thankfulness from your side, too, which you can express by giving this article a “clap” or by leaving some feedback in the comments!

--

--