loading...
Cover image for An introduction to Vue.js - Chapter 3 - Components (Part II)

An introduction to Vue.js - Chapter 3 - Components (Part II)

neradev profile image Moritz Schramm Updated on ・5 min read

Series overview

Chapter 1
Chapter 2
Chapter 3
Chapter 4
Chapter 5

Foreword

First of all: Thanks for the great support on dev.to and Twitter!

I added a table of contents at the beginning of every chapter so that you can easily jump between them. I recommend to read the other chapters before starting with this one.

This time we will try to extend our button component and make it a little more useful.

I will always upload the code to this github repository.

Properties

The first "quest" would be to extend our button so that we can set the text that we want to use depending on the place were we use it, since we do not want all our buttons to have the text "Click me!".

The requirements to our button text would be:

  • It can be set at the place where the button is used.
  • It defaults to "Click me!" if no text is given.

The answer to solve this problems are properties.

Properties are like parameters of a function - just for components. They can be set via the DOM were it will be used. Moreover we can display a property in our template or used even in function (we will see later).

But how to define a property on a components? The keyword for that is props. Its an object that export as well which contains multiple property configurations.

import template from './button.html';

export default {
    name: 'vg-button',
    template,
    props: {
    }
};

A property configuration can consists multiple parameters. For now we will concentrate on type, required and default.

type is the data type of the property. It could for example have the value String, Number or Boolean. For our button text we would use String since it should be some sort of text.

With the help of required we can define a property as needed to be passed when using this component. For our button I will leave it as not required since we are providing a default text.

default is actually the default value of the property.

So the definition of our text property should look like that.

import template from './button.html';

export default {
    name: 'vg-button',
    template,
    props: {
        text: {
            type: String,
            required: false,
            default: 'Click me!'
        }
    }
};

But how can we now display this text in our template?

For that we will using the Directives of Vue.

The easiest one would be just displaying text (actually that what we are looking for). There are two ways of doing that within our template file. (app/components/button/button.html)

Option 1

<button role="button" class="button">
    {{ text }}
</button>

Option 2

<button role="button" class="button" v-text="text"></button>

I personally prefer the first option.

Now we want to set the button text in our hello component to Foo Bar. This is actually pretty easy. In the template file of the components (app/components/hello/hello.html) we need to add just an attribute to the DOM node:

<div class="app">
    <h1>Hello World</h1>
    <vg-button text="Foo Bar" />
</div>

If you now build and open the app, you should now see that the button has the text "Foo Bar".

Methods

Of course we want our button something to do. For the begin we want our button to print the text that it has to the console.

Methods can be easily defined on a component by exporting the methods object.

import template from './button.html';

export default {
    name: 'vg-button',
    template,
    props: {
        text: {
            type: String,
            required: false,
            default: 'Click me!'
        }
    },
    methods: {
    }
};

If you use this within a method I would recommend you to use function and never a arrow function. With this we can access our properties. So if we want to print our text property to the console it would look like that:

import template from './button.html';

export default {
    name: 'vg-button',
    template,
    props: {
        text: {
            type: String,
            required: false,
            default: 'Click me!'
        }
    },
    methods: {
        interact: function() {
            console.log(this.text);
        }
    }
};

If you build and open the app you will recognise that the button does not execute the method. We need to add this method as an event function to our button. Luckily Vue provides an easy way of event binding. Therefore we need to edit the template. When we add @eventname as an attribute to a native DOM node we can register a function to that. The events are not automatically bubbled up so you can not use them directly on you custom component node (we will take care about that in different chapter). In our case it would be @click="interact".

So our template (app/components/hello/hello.html) should now look like that:

<button role="button" class="button" @click="interact">
    {{ text }}
</button>

If you now build and open the app the button should work as expected. Yeah!

Data

Sometime we need some variables for keeping data without passing them at usage. Of course we could add property with required: false and an initial value using default but Vue provides another way. We can export a data object or a function returning an object. I personally like the way of having a function returning the data object. That would look like that:

import template from './button.html';

export default {
    name: 'vg-button',
    template,
    props: {
        text: {
            type: String,
            required: false,
            default: 'Click me!'
        }
    },
    data: () => ({

    }),
    methods: {
        interact: function() {
            console.log(this.text);
        }
    }
};

As an example usage we want our button to count the clicks and displayed it together with our button text.

So first we would add an data variable called interactCount with the initial value 0.

import template from './button.html';

export default {
    name: 'vg-button',
    template,
    props: {
        text: {
            type: String,
            required: false,
            default: 'Click me!'
        }
    },
    data: () => ({
        interactCount: 0
    }),
    methods: {
        interact: function() {
            console.log(this.text);
        }
    }
};

Now we would need to increment that number each time the button is clicked. For that I removed the console.log and replaced it with the increment.

import template from './button.html';

export default {
    name: 'vg-button',
    template,
    props: {
        text: {
            type: String,
            required: false,
            default: 'Click me!'
        }
    },
    data: () => ({
        interactCount: 0
    }),
    methods: {
        interact: function() {
            this.interactCount += 1;
        }
    }
};

As you can see we can access the data variables with this as well.

To display now the number we need to adapt the template and use the directives to display the full text.

<button role="button" class="button" @click="interact">
    {{ text }} - {{ interactCount }}
</button>

If you now build and open the app the button text should change, every time you click the button.

Done

I hope you like the guide. If you have any questions ask them on Twitter or in the comment section. I will try to answer a much as possible. I am happy about any possible feedback.

Next chapter will come in the next days.

Discussion

pic
Editor guide