Rapid prototyping with Vue.js

No Comments

When I started at codecentric, I had no clue about frontend frameworks. Sure, I knew my HTML and CSS and I did some dynamic pages with PHP, but who didn’t? The first frontend-only framework I seriously worked with was AngularJS. I had a hard time getting into it, which was mostly based on the fact that it was ill-used in our project setup. Instead of separate modules for different parts of the software, we had one giant controller that only got more and more code branches for all the little specialities that were necessary for our business cases.

After a while, our team broke up this massive pile of code. I was eager to help and got a better understanding of JavaScript and AngularJS every day. Today I am pretty familiar with AngularJS projects. Although there is one thing that’s always bothered me. Setting up a small Angular project, for example if you want to quickly try out an idea, can be pretty tedious.
I took a look at other frameworks (Angular2, React) in hope that they would be more easy to start a project with, but there you mostly start with an npm/webpack/whatever setup, which is often just totally overweight.

Then I came across Vue. And I really like how lightweight it can be. In this tutorial, I want to show you how quickly you can set up a dynamic webpage, even with REST functionality. A little bit of basic JavaScript knowledge is helpful here. You should also be familiar with the usage of your browser’s developer tools.

If you want to program along, create an index.html and paste this snippet. In the snippet I added some css styling, so the whole thing looks a little bit nicer.

Let’s start with a simple form:

<div class="row">
  <form>
    <label for="zip">Zip:</label>
    <input id="zip" type="text" placeholder="Insert ZIP" />
    <span class="weak hidden">Loading...</span>
  </form>
</div>
<div class="row">
  <label for="city">City</label>
  Matching City:
  <span class="match">Insert zip to display matching city</span>
</div>

This should render you the following form:

Rendered form

The form should take a valid (in this case German) ZIP and show the matching city.
Now let’s init Vue.js. Add a link to vue.js to the header:

<head>
   <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>

Then add a script snippet before the closing html tag where you init Vue:

<script type="text/javascript">
    new Vue({
        el: '#zip-loader',
        data: {
            city: 'Insert zip to display matching city'
        }
    });
</script>

We don’t have an Element ‘#zip-loader’ yet, so create a div around the existing form:

<div id="zip-loader"></div>

Replace the text ‘Insert zip to display matching city’ with {{ city }}, so that it looks like this:

Matching City: <span class="match">{{ city }}</span>

Reload the file. It should look the same. Only the text is now taken out of the data part of the Vue instance we created. Try changing the text in the city field. It should change in your form. If something’s wrong, check your browser console for errors. Vue is very verbose and it’s often easy to spot the mistakes.

Let’s register the user’s input. Add a ZIP field to the data section of your vue instance and set it to be an empty string:

data: {
  zip: '',
  ..
}

Bind the new field to the input field in the form. Now everything the users enter here will be directly bound to the ZIP field in the data section of our Vue instance.

  <input id="zip" type="text" placeholder="Insert ZIP" />

Now let’s add a method that is called when a letter is entered:

  <input type="text" />

Add a methods block in your Vue instance and define the method ‘parseZip’ in it. Let’s just log the value of the ZIP field.

  methods:{ 
    parseZip: function(){
    console.log(this.zip);
  }
}

Now if you enter something in the input field, your browser should log it to the console. By the way, this references your Vue instance.

Now that we get user input, we need to do something with it. We want to load a matching city for an entered ZIP. Since we don’t have a backend, we use a public API for this. http://api.zippopotam.us/ offers a very easy to use API. If you call http://api.zippopotam.us/de/42697 (the ZIP of the city Solingen in Germany), you get a nice JSON object that holds all the necessary information:

{
  "post code": "42697",
  "country": "Germany",
  "country abbreviation": "DE",
  "places": [{
    "place name": "Solingen",
    "longitude": "51.1611",
    "state": "Nordrhein-Westfalen",
    "state abbreviation": "NW",
    "latitude": "05122"
  }]
}

Vue cannot make REST calls. So we need another library for this. I use axios, but you can use any REST library you like. To embed it, just add the JavaScript source to the header:

<head>
     <script src="https://unpkg.com/axios/dist/axios.min.js"> </script>
</head>

This enables you to make a GET call in the parseZip method:

parseZip: function(){
  axios.get('http://api.zippopotam.us/de/42697')
  .then(function(response){
  console.log(response.data);
  })
}

Instead of logging the content of the ZIP field, we now make a REST call every time the user enters a key. The resulting data is then logged to the browser console.

Now modify the REST URL to take the ZIP from the data object of our Vue instance:

  axios.get(`http://api.zippopotam.us/de/${this.zip}`)

Note that I changed the single quotes to backticks here, so I can use template strings.

Since ZIP codes in Germany are generally 5 digits long, add a safeguard around the method, so that the API is not called with a definitely invalid ZIP. Also, change the log function to log the retrieved city. Take a look at the JSON object again, to better understand the syntax I used here.

if (this.zip.length === 5) {
  axios.get(`http://api.zippopotam.us/de/${this.zip}`).then(function(response) {
  console.log(response.data.places[0]['place name']);
  })
}

To show the retrieved city on the website, just assign it to the data object. Note: We need to assign the Vue instance to a variable first, because the callback function of the REST call creates a new scope where this doesn’t reference the Vue instance any more.

const myApp = this;
if (this.zip.length === 5) {
  axios.get(`http://api.zippopotam.us/de/${this.zip}`)
  .then(function (response) {
  myApp.city = response.data.places[0]['place name'];
  })
}

If you now enter a valid ZIP into the input form, it should show the name of the matching city.

Now our basic functionality is done. Let’s finish up with a little error handling and a loading message.

To show an error message, add a catch block to the get method.

axios.get(`http://api.zippopotam.us/de/${this.zip}`)
.then(function (response) {
  myApp.city = response.data.places[0]['place name'];
})
.catch(function(){
  myApp.city = 'Not a valid zip code';
})

To show a loading message, we need a little additional CSS:

<style>.visible {
  display: inline;
}
…
<style>

Add a loading flag to the data section:

data: {
           …
            loading: false
        }

Set the flag to true before the GET call:

…
myApp.loading = true; 
axios.get(`http://api.zippopotam.us/de/${this.zip}`)

And set it to false when loading is done:

.then(function (response) {
  myApp.city = response.data.places[0]['place name'];
  myApp.loading = false;
})
.catch(function () {
  myApp.city = 'Not a valid zip code';
  myApp.loading = false;
})

Now all there is left is changing the CSS class of the Loading… text according to the flag.

<span v-bind:class="{visible: loading}" class="weak hidden">Loading...</span>

That’s it. We’re done. We created a dynamic, RESTful web page without any build or packaging tools. This shows why Vue is a great framework if you want to try out something very quick.

If this article got you interested in Vue.js and you want to start something more sophisticated, I suggest to take a look at this article of my colleague Jonas Hecht. He describes how to bootstrap a full stack vue.js project using Spring Boot.

You can look up the final code at https://github.com/Guysbert/vue-rapid-protoyping or play with it in this codepen.

See the Pen Rapid protoyping with vue by Andreas Houben (@ahouben) on CodePen.

Andreas Houben

Andreas is a Senior Software Engineer who likes to do the things right. And hopefully the right things 🙂

Comment

Your email address will not be published. Required fields are marked *