Codementor Events

Going Meta: How I Used Vue.js to Build a Small Quiz About Vue.js

Published Jul 25, 2017Last updated Jan 20, 2018
Going Meta: How I Used Vue.js to Build a Small Quiz About Vue.js

This post is about Vue.js, software development, and education. You will get some philosophical reflections about how quickly the world is changing and how education should adapt to it. You will also get some practical introduction to Vue.js. After you’ve finished reading this post, you will be able to use Vue.js right away and build reactive interfaces right now. Ready? Go!


Table of Contents


Who am I?

My name is Olga Filipova, and I am a software engineer, published author, wife, mother, and education lover. I was born in Ukraine, which at the time of my birth, still belonged to the Soviet Union (to be honest, I’m happy it doesn't anymore).

At the age of 20, I moved to sunny Portugal, where I spent 13 happy years. I studied computer science at the University of Coimbra, one of the oldest universities in Europe that simultaneously keeps its old traditions and moves forwards with the newest trends and technologies. After graduating, I worked at a startup called Feedzai for 6 years.

Now, I'm living in Berlin and working as a lead software engineer at Meetrics. I am also a co-founder of an ambitious Ukraine-based educational project called EdEra.

As a big part of the EdEra Team, I care deeply about software development and education.

Why do I care?

I have two big passions in my life: software development and education.

Let's start with education. I am one of those people who firmly believe that the best investment you can make comes from learning. I also believe that the whole process of education and learning is changing drastically. With new technologies, our lifestyles have changed a lot. Everything that surrounds us should be adapted to the new process of thinking. People now think fast, do fast, act fast. Things change fast. We can't afford to teach computer science for 5 years anymore because in 5 years, everything that you've learned will become obsolete. Of course, there are some solid principles that form the foundation and should take some time to be learned. So the educational system should now follow some hybrid approaches. And it has to be fun.

That's why we created EdEra — to prove that learning is actually fun. We wanted to prove that you can learn even if you think that you are simply playing a game. We wanted to change the whole system. During the 3 years of working in the education industry, we developed online courses, implemented blended learning in Ukrainian schools, and created interactive online books with integrated quizzes. We worked with different entities and organizations and built a strong understanding of cognitive processes that are triggered when you use certain teaching techniques.

EdEra

We also realized that we still have a lot of work to do. Nowadays, technology is developing so fast — education should keep pace with this progress.

This leads us to the second thing I care a lot about: software development.

I've been working as a front-end software engineer for almost 8 years. In the past 8 years, I've seen huge progress in web development. The possibilities that existing frameworks and tools provide are scary. The simplicity of building responsive progressive applications is astonishing. With that said, the difficulty of choosing the right tools in different cases increases by the hour. The open source community is growing and has continually been working on new tools, projects, libraries, frameworks, and more. It is nearly impossible to make a choice. Where should I deploy? AWS? Heroku? Firebase? Just GIT and cronjob+script? What about CI solutions? And database? Elastic search? GraphQL? What about the templating? Plain HTML doesn't sound so hipster, should I use jade? Handlebars? JSX? Should I even talk about module bundlers and package managers?

Back in the days when I was writing my master thesis, I included a section called "state of the art", where, for each chosen technology, I presented a comparison table of existing tools for a specific purpose. I only had 3 things to compare in the databases comparison sub-section. If I had to write this section for my master’s thesis again today, I’d rather just give up the degree!

Web applications are getting more and more sophisticated, and web development today requires building complex interfaces at a fast pace. We live in a world where rapid application development is a necessity — we have to develop applications almost immediately after prototyping. We need to give immediate feedback. We need to have tools that allow us to do this without spending time on repetitive tasks.

Why Vue.js?

When I was working at Feedzai in Portugal, a very complex new feature came up once. We had to build a pretty complex proof of concept prototype in a very short time. We were using Backbone.js in the front-end, which turned out to be unreliable. We didn’t need any MVC structure; all we needed was to build a view layer with lots of similar elements and items in it. This is how we discovered Vue.js. It turned out to have a pretty nice learning curve and was totally adequate for our needs.

Its reusable components system helped us to avoid repetitive code, allowed us to work in parallel on different parts of the system, and then easily glued them together. I loved using Vue.js then and continued using it in a small project afterwards. This is why I’ve listed Vue.js as one of the frameworks I’m familiar with on my Linkedin profile. Maybe that’s why Packt Publishing contacted me and asked whether I would be interested in writing a book about Vue.js. I hesitated because I didn't think I was a Vue.js guru.

NotAGuru
Photo from VueConf2017, lightning talk "How I wrote a book about Vue.js"

However, I also realized that no one is truly a guru in anything, and I should probably give it a try. It turned out to be an amazing experience — here’s the book if you’re interested: Learning Vue.js 2. Currently, I am writing a second book called Web Development with Bootstrap and Vue.js. I am enjoying the process of writing for several reasons:

  • First, the approach is to develop an application from scratch until its deployment. The application we were building during the time the book was being written is one that I’ve always wanted to build but never had time for (it is a pomodoro timer with embedded office workouts)
  • Second, it integrates with Firebase back-end and turns out, is great and easy to use
  • Third, and most importantly, Vue.js is simple, fun, and great to use! The documentation is great, the community is awesome, the learning curve is smooth, and the process of web development becomes so enjoyable!

So, again, why Vue.js?

  • It's easy to get started. There is no need to install the whole npm on your computer. Just download vue.js, insert into the <script> tags, and use it. Just instantiate it as new Vue({el: '#app'}). Everything inside the #app element will immediately become bound to reactivity.
  • It's reactive. It is easily reactive. No need to learn a new language, just use your favorite JavaScript version or any other language that compiles into JavaScript. No need to change your logic. Just bind data to your elements using the handlebars {{ }} notation or v-* attribute. You can easily bind classes, styles, properties, attributes, or even transition to the data and your components.
  • Not just components but reusable components. These components can be created using simple Vue.component() syntax or you can have single file components. These single file components follow so easy to any web-developer to understand style, template, and script areas.

Because it’s all about reactivity

Let’s imagine that you need to implement a way to add a quiz question to the system. Imagine this as a multiple choice question with two options. In terms of the markup for the question form, it’s easy — it can be a textarea for the question itself and two text inputs for the answers. So it would look as something like this:

<h2>Create your multiple-choice question here</h2>
<label for="question">Type your question</label>
<textarea id="question" cols="30" rows="3"></textarea>
<label for="option1">Option 1</label>
<input id="option1" type="text">
<label for="option2">Option 2</label>
<input id="option2" type="text">

The result would look something like this:

Form

Imagine now that you would like to have immediate visual feedback of how this question will look like. You would create a markup that represents the question and two multiple choice radio buttons, something like this:

<div id="show-question"></div>
<label for="answer1"><input name="answers" id="answer1" type="radio"> <span></span></label>
<label for="answer2"><input name="answers" id="answer2" type="radio"> <span></span></label>

After that, you’d have to find a way of connecting the data from your inputs with its representation elements. If you use jQuery, you’d have to attach the event handler to each of the input elements, listen to the keyup event, and update the corresponding visual elements with the received data. So, your JavaScript code would look something as the following:

$("#question").keyup(() => {
  $("#show-question").text($("#question").val())
});
$("#option1").keyup(() => {
  $("label[for=answer1] span").text($("#option1").val())
});
$("#option2").keyup(() => {
  $("label[for=answer2] span").text($("#option2").val())
});

With Vue.js, you’d attach the data model to your inputs and access them using the handlebars notation: {{}}. So, first, you have to define the markup area of your application, e.g. wrap it in the div with some specific id:

<div id="app">
  <...>
</div>

Now you create a Vue application attached to this element:

new Vue({
  el: '#app'
})

All the elements inside the #app div are very special now. Now they all have listeners attached and if any of the application's data attached to any of these elements change, they will immediately be propagated to all the other elements that use this data. Wait, what about the data? The data is another option that can be passed to the Vue instance. In our case, we will pass a question and two options:

new Vue({
  el: '#app',
  data: {
    question: '',
    option1: '',
    option2: ''
  }
})

We are ready to use this data inside the template. Change, for example, the #show-question div:

<div id="show-question">{{ question }}</div>

Change the question string in the data passed to the Vue instance. You will see that the data is correctly rendered. If somewhere in the middle of your application you recalculate this value, the change will be easily propagated to the element. This is the so-called one-way data binding. The data changes immediately flow from the data itself to the elements to which this data is attached. Vue.js also supports two-way data bindings, so if you attach the data to some specific elements, the changes will flow both ways. Input and textarea are one of the elements to which you can bound a reactive Vue.js data. This is done via the v-model attribute. Just pass it to your input, and you will see magic happen:

<textarea id="question" cols="30" rows="3" v-model="question"></textarea>

Now, if you type in your textarea, you will immediately see how the question holding div always represent the same content as you type it in the textarea. Bind two options to the corresponding input elements and radio buttons. Awesome, you’ve just built the WYSIWYG quiz editor!

WYSIWYG quiz editor

The amount of code for this is amazing:

<body>
  <div id="app" class="container">
    <h2>Questions</h2>
    <div>{{question}}</div>
    <label for="option1"><input name="answers" type="radio" :val="option1"> {{option1}}</label>
    <label for="option2"><input name="answers" type="radio" :val="option2"> {{option2}}</label>
    
    <hr>
    <h2>Create your multiple-choice question here</h2>
    <label for="question">Type your question</label>
    <textarea v-model="question" id="question" cols="30" rows="3"></textarea>
    <label for="option1">Option 1</label>
    <input type="text" v-model="option1">
    <label for="option2">Option 2</label>
    <input type="text" v-model="option2">
  </div>
  <script src="vue.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: {
        question: '',
        option1: '',
        option2: ''
      }
    })
  </script>
</body>

Because it’s about easy to use directives

Vue.js comes with lots of easy to understand and easy to use directives. v-bind is probably one of the most important. It allows you to bind nearly everything — attributes, classes, properties, etc. For example, let’s bind classes success to the correct option and class danger to the incorrect option. For this, I will introduce one more reactive data item called correctOption. I’ll bind it to the numeric input on the quiz question creation:

<label for="correctOption">Correct option</label>
<input type="number" v-model="correctOption">

Then I define my classes as simple as follows:

.success {
  border: 1px solid green;
}
.danger {
  border: 1px solid red;
}

Now, using the directive v-bind:class, I will bind these classes to the corresponding radio buttons accordingly to the chosen value.

Actually, instead of writing v-bind:class you can simply write :class.

<label :class="{success:correctOption===0, danger:correctOption!==0}" for="option1"><input v-model="picked" name="answers" type="radio"> {{option1}}</label>

If you do the same for option 2, you’llend up with something like this:

correct/wrong classes

It actually doesn’t seem right because we would probably only want the options to be highlighted after they’ve been selected. Well, just add a new attribute, let’s say, selectedValue and bind it to the radio buttons group value. Then slightly change the condition for the classes by adding a condition for selectedValue, which is being defined.

This worked nice with two options, but what if we had 20 different options? Can you imagine rendering all this stuff for each of the options? That is why there is another nice directive called v-for. This directive allows us to avoid writing repetitive code. Let’s pass our options into the array and use this array within a v-for directive:

new Vue({
  el: '#app',
  data: {
    question: '',
    options: [{text: ''}, {text: ''}],
    correctOption: 0,
    picked: ''
  }
})

v-for attribute is pretty easy to use. If you have a list of items, you just use it in your template like this:

<ul>
  <li v-for="item in items">{{ item }}</li>
</ul>

The item is not necessarily a string. It can be a number, an array, or an object. In our case of options, we have a list of objects. And we can easily display it like this:

<label v-for="option in options"><input name="answers" type="radio"> {{option.text}}</label>

If you need to access the index of the list, you can use v-for as follows:

<li v-for="(item, index) in items">{{ item }} {{index}}</li>

So in our case, to display the options to be filled, we would do something like this:

<div v-for="(option,index) in options">
  <label>Option {{index}}</label>
  <input type="text" v-model="option.text">
</div>

We have dropped the correct/incorrect styling for now but we'll come back to them in a sec!

Because it’s about reusable components

Knowing a v-for attribute gives us a lot of power. We can now render multiple options and even multiple questions. We can reuse questions in different pages — one page for the course instructor and another one for the student. The data is reactive, so we’d change it in one place, and the other one would be updated and can be reused in some other place, which is so great. But… There’s always a “but”, right? Isn’t it tedious and frustrating to have to always write HTML code to render our questions? Even with a v-for attribute it might become a mess to have to always rewrite the HTML in all the places that we need it.

The big and great thing about Vue is that it offers a nice and easy way to define and use components. For example, we can easily extract our question into a component:

var question = {
  template: `
    <div id="question">
      <div>{{question}}</div>
      <label v-for="option in options">
        <input name="answers" type="radio"> {{option.text}}</label>
      </label>
    </div>
  `,
  props: ['question', 'options']
};

And then use it within our main Vue application:

new Vue({
  el: '#app',
  data: {
    question: '',
    options: [{text: ''}, {text: ''}],
    correctOption: 0,
    picked: ''
  },
  components: {
    question
  }
})

And then instead of using the actual markup, just invoke the question tag and pass the needed properties (question and options) to it:

<div id="app" class="container">
  <h2>Questions</h2>
    <question :question="question" :options="options"></question>
  <hr>
  <...>
</div>

That's it!

Because it’s about simplicity

Well, Vue.js is awesomely simple. Check out a very simple quiz that I prepared for you using Vue.js. Check out the Reults tab to see how elegant it is:

jsfiddle

If you prefer some more sophisticated way of creating complex applications (e.g. using webpack loaders, having unit and end2end tests), just use vue-cli with webpack template to initialize your application and start using single file components right away!

# install vue-cli
$ npm install --global vue-cli
# create a new project
$ vue init webpack my-awesome-project
# install dependencies
$ cd my-awesome-project
$ npm install
$ npm run dev

I really hope that you correctly answered the first question of the quiz:

Isn't Vue awesome?

Post Scriptum

My dream is to build a new platform for online courses. This platform would combine all current trends in education, offer the possibility of creating micro-learning courses as well as massive courses, combine them, build paths, and provide different levels of expertise and mechanisms of adaptive learning.

The platform would allow users access to these courses not only for online education but also for blended and offline learning. I would build this platform with Vue.js and the newest trends in progression web applications development. If you are reading this and willing to help with advice, or expertise, or even an investment, drop me a message!

Discover and read more posts from Olga Filipova
get started
post comments6Replies
Erick Petrucelli
7 years ago

Congratulations Olga, your post is really interesting, really better than many to-do list tutorials out there. I’m teaching Vue at the Faculty of Technology of Taquaritinga, Brazil, for 1 year now. Ironically, I use Moodle a lot and already dreamed about a new learning environment built with modern tools like Vue. If we can help you in some way, keep in touch.

Kurt D Caton
7 years ago

Thanks for the tutorial, Olga. Just starting to learn View.js. Ordered your book “Learning View.js 2” a few minutes ago from Amazon.

Dave Trimble
7 years ago

I’m working my way through your article and, as of a few minutes ago, I’m looking forward to your November publication. You will meet your publication date won’t you? ;o)

Vue, Bootstrap, and Firebase who could ask for anything more. Unless you added Firebase to this post. I have a softspot for training software.

Also, I apologize for the election of another leader who could be added to your “lying” chorus’ script. ;0)

Olga Filipova
7 years ago

Hi Dave, I met my publication date :) http://a.co/5PZYdO6 Cheers!

Dave Trimble
7 years ago

Congratulations!

Bought.

Now let’s see how practical it is to work through the Kindle version. Would you like feedback as I work through it? Of course you know I’ll ask a question or two along the way. ;o)

Olga Filipova
7 years ago

thanks a lot! sure, questions and feedback are always more than welcome :)

Show more replies