This is the second part of our article series “An introduction to Vue.js”. For the first part click here >>
Whether you are fortunate enough to start a whole new project or have to face the even more exciting challenge of continuing an existing and grown project – there are always decisions to be made, especially at the beginning. A not-so-insignificant decision is how to equip your toolbox.
The programming language should already be set in most cases, but there are still some imposing questions: How do I write my source code? More importantly, how do I organize it? How do I translate my technical requirements into clean, preferably high-quality and well maintainable source code that developers can survey and understand with ease? Frameworks help us in this context. Vue.js [1] is such a framework and a very versatile and universal one at that.
Why use Vue.js?
There is versatility to Vue.js, which is expressed with the fact that you can get used to it relatively quickly. Any web developer experienced with HTML, CSS, or JavaScript can quickly become familiar with Vue.js. No expert knowledge is required in this context.
Even the popular and widespread JavaScript applications like TypeScript or JSX can be used together with Vue.js, although Vue.js does not necessarily require any of these extensions. That is the whole idea behind Vue.js – to keep things simple. In this regard, Vue.js is dedicated in its entirety to the JavaScript language, just like the saying “Cobbler, stick to your trade” goes.
There is also the pleasant side effect that you can test your applications even easier with Vue.js, because everything in there is pure JavaScript. With test frameworks like Mocha [2] or Jest [3], almost everything can be tested efficiently without trouble. What’s more, because Vue.js is based on core technologies like HTML, CSS, and JavaScript, it can be easily integrated into existing projects. In this way, small individual components can be isolated and are brought under the control of Vue.js. The framework can be introduced step by step. Vue.js can also be useful for fast prototyping, for example, when you need to have something up and running at short notice to be able to quickly get feedback from the future user of the application.
In addition to its excellent performance, there are other soft factors which speak in favor of this framework. For example, the documentation that is available on the website of Vue.js quite helpful. It’s often said that open source projects have poor documentation or even none at all. This is by no means true for Vue.js. The functioning community should not remain unmentioned. Developers in the Vue.js community are always friendly and understanding. Questions are also usually answered in a quick, uncomplicated, and decent manner.
Everything put together
The term component is derived from the Latin verb componere and it means compounding [4]. Houses are a good example of component orientation outside of IT. For example:
Within the context of civil engineering, a hole must be dug for the basement component, whereby the basement does also consists of its own components – such as floor slabs, white tubs and the ceiling. The ground floor component is located in the basement, followed by the upper floor and roof. Each of these individual components is made up of its own components. For each of these components, there are specialists who plan, implement, and maintain them. Civil engineers, masons, cleaners, electricians, and carpenters – everyone is a specialist and a master craftsman in their field.
Another good comparison shows quite clearly how the results can look if you think that you can do everything on your own in Figure 1: The attempt of a student of the Royal College of Arts in London. Unfortunately, the topic of component- orientation is still too rarely taken seriously in software development today. It is also unfortunate that many developers think they have to be particularly creative and reinvent the wheel over and over again. Cut it out. The good news is that modern web application frameworks such as React, Angular, or Vue.js not only support us to think more component-orientated at this point, but rather that they force us to so.
Components in Vue.js: No reusability at all costs
The component concept of Vue.js aims to create easily maintainable and reusable units of code. But reusability does not mean reuse at all costs. It is rather a question of dividing a functional requirement, for example an application for entering classified ads, into small components. The aim is to provide a better overview of these small component modules. The application is divided into a hierarchical structure of software modules of which it is composed piece by piece.
Of course, it does make sense to reuse one of these modules in a different context if needed. However, it should not be the developer’s claim to develop reusability and generic routines at all costs. Therein lies the danger that we create our own problems by unconsciously bringing complexity into the project. To be honest, it is also no problem if the code is kept redundant in one place or another. A carpenter doesn’t use just one saw during construction; they use saws specifically tailored to their needs. Redundancy is not bad per se; if it does serve a better understanding of the software architecture, then it is most certainly no mistake.
The first component
If you look at a typical web application, you will usually find a display in the upper right corner showing which user is currently logged in. This can be achieved through a component, a module that can be reused in other parts of the application. The form for recording the classified ads, in the core a <form>, can be the next component. Other components of the form such as a date selection can also be implemented as child components, which are used by the classified ad entry component (the so-called parent component).
Actually, the components are grouped HTML. However, if a component consisted only of HTML, the whole thing would be a boring and static matter. Through CSS and JavaScript, components are glammed up and become dynamic. Frameworks such as React, Angular, and Vue.js offer us the possibility to unite all of these parts into components in its own specific way. In the case of Vue.js, it is meant quite literally. Components allow you to add new tags to HTML (custom tags). In this way the log-in component becomes a <login> tag and the entire classified ad entry form can suddenly be used with a simple tag, like < small-advertisement-entry/>.
Listing 1 shows how easy it is to create components in Vue.js. Through the static component method, the component is registered to the Vue.js object. Basically, Vue.js components, like Vue.js instances, are defined as a JavaScript array with name-value pairs. Thus, the hello-world-component in listing 1 is registered under the name hello-world. The HTML fragment is defined in the template option, which is to be output when using the <hello-world> tag. You may be wondering now why the component was not called hello or helloWorld; if that is the case, then please refer to the official Vue.js style guide [5]. Since there is no real convention on how to name custom HTML tags, here’s a few valuable tips. You should avoid using single words to evade potential name conflicts. Apart from the fact that it is highly unlikely that there will ever be a <hello> tag in the HTML standard, the probability there will be a <hello-world> tag is close to zero.
According to the style guide, the use of Camel Case is definitely allowed. However, in practice it has been shown that a Camel-Case-like component name such as HelloWorld does not work right away in the Chrome browser and that it is interpreted as helloworld. This leads to mistakes. Therefore, multi-wording separated by hyphens is recommended here.
Listing 1: The first Vue.js component
<html> <head> <script src="https://unpkg.com/vue"></script> </head> <body> <div id="app"> <hello-world /> </div> <script> Vue.component('hello-world', { template: '<div>Hello World from Vue-Component</div>' }); new Vue ({ el: "#app" }); </script> </body> </html>
Globally registered Vue.js components, such as in Listing 1, can be used anywhere in the application, even if individual components are subject to the control of different Vue.js instances. Of course, components can also be bound to individual Vue.js instances by logging on to the desired Vue.js instance with the components option. Listing 2 depicts an example. The solution, which is presented in the listing, is to define the component as a constant in advance. This is certainly the more sensible approach for registering the components with other Vuw.js instances later if required. However, it is also possible to make the registry directly at the components option.
It is important to understand that components are reusable Vue.js instances. Therefore, Vue.js components share many properties with Vue.js instances. Options like data, computed, watch, or even methods can be used for components, just as you are used to with normal Vue.js instances. The event model exists analogously for components. There are no more specific options, such as el, for binding a Vue.js instance to a specific HTML tag. This is not surprising as components themselves become HTML tags. The number selection component is deliberately used multiple times in Listing 2. An attentive reader will quickly realize that here each component instance is able to manage its own state. This is made possible by defining a function instead of the data in the data option – in contrast to Vue.js instances.
Theoretically, it would be conceivable that a developer, instead of this (correct) code
data: function() { return { count: 0 } }
writes the following (wrong) variant:
data: { count: 0 }
Regardless, as Vue.js would not accept and execute the simplified variant at all, it should be clear that this cannot work for potentially multiple instances of the component.
Listing 2: To bind a component directly to a Vue.js instance and use it multiple times
<html> <head> <script src="https://unpkg.com/vue"></script> </head> <body> <div id="app"> <select-number initial='100' suffix='EUR'> </select-number> <select-number> </select-number> <select-number initial='200' suffix='SFR'> </select-number> </div> <script> const SelectNumberComponent = ('select-number', { data: function() { return { count: this.initial } }, // props: ['suffix', 'initial'], props: { suffix: { type: String, required: true }, initial: { type: String, required: false, default: '10' } }, template: "<div><input type='number' v-model='count'> Selected number: {{ count }} {{ suffix }}</div>" }); const my = new Vue ({ el: "#app", components: { 'select-number': SelectNumberComponent } }); </script> </body> </html>
From top to bottom
An important concept of Vue.js components is their unique selling proposition. Components should be able to stand for themselves and have as few interrelationships and relationships as possible with other higher-level components. Those who stick to this concept will end up with a modular system where applications can be simply plugged together. Moreover, you are rewarded with small, easily manageable software blocks that are easier to maintain. The topic of testability should not remain unmentioned here; this is because small, self-contained, and isolated software units can be covered much easier (and faster) with unit tests.
Another basic principle in Vue.js components is that data may only ever be passed down. Interdependence should not occur, because the programming model of Vue.js provides only one way: from top to bottom. To pass data down, the option props is offered, which stands for properties. Here, you can pass either an array of string objects or a collection of objects. Listing 2 shows an example. The commented-out props demonstrates the variant with the string array and the values after the initial and suffix – the actual data is passed in the form of properties on the component tag – arrive in the component. The second props variant allows for more explicit specifications. In Vue.js, this feature is called Props Validation. Among other things, you can also define which type of data is expected (String, Number, Boolean, Functions, Objects) and whether a property must be obligatorily committed (required). The default values can also be defined here.
With the second <select-number> component in Listing 2, neither an initial nor a suffix value is passed. The counter starts with the value 10 in this component instance, but an error is displayed in the console. This indicates that the suffix is a required field for which no value has been passed.
The typical Java developer will now ask themselves how they can explicitly access the data or the state of a particular component instance, if the data can only be passed from top to bottom. Normally, you would iterate through the list of available components and call a getter.
That is exactly what you are not supposed to do in Vue.js. Passing data from parent to child simply means that the data is held and managed in the topmost, if not even in the root component. Individual data components are pressed downwards, so changes to the data records thus automatically remain at the very top of the data source.
Custom events and references
Hopefully, for the rare cases in which a child component has to pass on information upwards, you can fall back on a special event handling: the custom events. Here, the child component triggers an event and notifies its parent. To do this, the parent component must be bound to an event using the v-on directive. You must also specify which JavaScript function is to be called when this event occurs. In the child component, you can use the $emit function provided by Vue.js to trigger an event. It is here, where the event name and data are to be transferred. The superordinate component listens in on this event, is notified, and receives the data. This principle of passing from top to bottom is good style in Vue.js applications and should not be broken.
For those hopefully even rarer cases where there is no other way around it and you have to access internals of child components, Vue.js also offers the possibility of working with references. In practice, this means that you set the ref property for each component you want to access and assign a unique name to the component. In the superordinate component, the $refs function gives you the chance to get a list of all components marked with ref. This way, you can easily reach into individual components.
Single file components
For a Vue.js developer, it is important to shape the source code of an application in such a way that it can be further developed in the future without any obstacles. Components are an important tool in this context. If all components, as it is the case in Listing 2, are distributed directly to one HTML file or to several JavaScript files, then the source code may still be too compressed. If you intend to change your component B later, then you will still be bothered by the source code of the components A and C, which can lead to unnecessary context switches and distracted developers.
So, in order to make a clear cut in the level of data, each component could be led into its own JavaScript file. This would undoubtedly work, however, the problem remains – only pure JavaScript can be used. HTML or CSS component parts must be packed in string.
Modern IDEs like Visual Studio Code, Atom, or Webstorm all come with syntax highlighting and code completion. As a developer, of course you want to use this. React’s solution to this problem is called JSX. The idea of JSX (JavaScript eXtended) is to mix HTML and JavaScript. Modern build systems such as webpack [6] or Browserify help to generate executable JavaScript from this special format.
Vue.js ventures in a similar direction with its single file components, but it is based on a completely different concept. The basic idea is to keep all components of the component as legible as possible in one file. The individual components are therefore separated by special tags. The HTML part is stored within two <template> tags, the JavaScript code is in the <script> area, and the <style> area is provided for CSS parts. Finally, the file is saved with the special file extension .vue. Most IDEs can now handle Vue.js files. Of course, Single File Components are not easily executable; they also have to be brought into shape with the help of a build system. This means that JavaScript is compiled or transpiled. Fortunately, Vue.js CLI [7] provides a template to fully configure webpack.
Vue.js Tutorial – Conclusion
With Vue.js, component-based applications can be built after a relatively short familiarization phase. Vue.js pays particular attention to providing the developer with tools to structure the source code as best as possible. Of course, this series of articles could not look at Vue.js in depth. We hope that we were able to arouse curiosity about this interesting, up-and-coming framework. And please don’t forget: take a look at JavaScript and think in components! We’re all living in a component-oriented world!
Links & Literature
[1] Vue.js: https://vuejs.org/
[2] Mocha website: https://mochajs.org/
[3] Jest website: https://facebook.github.io/jest/
[4] Term explanation component : https://www.duden.de/rechtschreibung/Komponente
[5] The official Vue.js styleguide: https://vuejs.org/v2/style-guide/
[6] webpack website: https://webpack.js.org/
[7] Vue.js CLI command line tool: https://github.com/vuejs/vue-cli
Discover the program of iJS 2019 in London:
→ It’s alive! Dynamic Components in Angular