DEV Community

Friday Godswill
Friday Godswill

Posted on

Components in VueJs

Components make our codes reusable and enable us to stick to the software development principle of D.R.Y (Don’t Repeat Yourself). Components are blocks of code which extend basic HTML markup behaviour and can be used over and over for different purposes. What this means is that components in Vue look like basic HTML elements, but they are more configurable and hence, can perform more functions than a plain HTML element. Components can also contain other components, this makes our front end very robust and quite modular.

Modern web applications are composed of many parts, and the best way to keep track of all the moving parts would be to abstract them into different small parts (components), making them easy to structure, use and maintain. So that in the end, you might end up with code similar to this for an entire page, that performs a lot of functions:



<html>
  <head>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
  </head>

  <div id='app'>
    <app-header :links="links"></app-header>
    <app-sidebar :items="items"></app-sidebar>
    <app-body></app-body>
    <app-footer></app-footer>
  </div>
</html>    

Enter fullscreen mode Exit fullscreen mode

You’d agree with me that as a maintainer, code like this is very neat and straight to the point, and it would not take too much time to figure out what’s going on and what section does what.

Components in Vue can be created in two ways, they can be created in a separate file, then imported using the Es6 import statement. Or they can be registered inside the base JavaScript file and used directly.

For the purpose of this article, we are going to create a basic component that takes in a user object, outputs a list, and alerts the user details when each user is clicked.
With this, we will demonstrate:

  1. Creating Components,
  2. Passing Data to components via Props,
  3. List Rendering,
  4. Emitting events from a child component,
  5. Listening for events on a parent component, and
  6. Handling Emitted events

If you are new to Vue, you can check out the Official Documentation to get started.

If you'd like to skip on ahead to the finished project, there's a Code pen where the finished project is hosted.

Setting Up

There are two ways to setup your Vue project.

  1. Using the Webpack build tool or
  2. Using Vue via the Vue CDN.

Let us explore defining our components inside our JavaScript file, using the Vue CDN.

To get started, make a plain old HTML File, and include the Vue JavaScript file from the CDN.

<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
Enter fullscreen mode Exit fullscreen mode

This makes sure that Vue is available in the project. Next, we add a <script> tag inside the body tag. This is where our Code will live.

By now, Your Project should look like this:


<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>   

    <script type="text/javascript">
      //Our Codes, Here            
    </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

We are now ready to begin writing our code.
Just to make sure that Vue Js is properly installed, let’s create a “Hello Vue” application.
Add a div tag within the body tag of your HTML file, give it an id of “app".
Within the div tag, copy and paste this: {{message}} the text in the double curly braces indicate a variable in Vue.

Within your script tag, copy and paste the following, we will explore what these mean in a moment.


let app = new Vue({
    el : "#app",
    data(){
      return{
        message: 'Hello Vue'
        }
    }
});
Enter fullscreen mode Exit fullscreen mode

What we have done above is,

  1. Instantiate a new Vue Object, telling it that the HTML element it should use, has an ID of app
  2. We have then provided a data object, that returns message
  3. Finally, we printed out the message variable defined in the data object above, into the HTML by typing in this: {{message}} the double curly braces indicate that their content is a variable.

By now, our entire Code Should look like this:


<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>

    <div id="app">
            {{message}}
    </div>
    <script type="text/javascript">
       let app = new Vue({
           el : "#app",
            data(){
              return{
                 message: 'Hello Vue'
              }
            }
       });

    </script>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

If we run this in the browser, we should get an output of “Hello Vue”.
Now that we have confirmed that Vue is properly setup, let’s get right to defining components in Vue.

Defining Our Component.

As previously stated, components can be created as a separate file altogether, or directly inside our main JavaScript file. For this tutorial, we are going to be defining our components directly inside our JavaScript file.

Components are registered using Vue.component('tag-name', options) command, where tag-name is the name that you want your component to bear and options is an object that defines the behaviour of the component. This makes the component globally available within the file and thus, can now be used in different cases.

Let’s start by defining a dummy component that does nothing but show a message on the screen. Let’s call this user-list. To follow along, create a new HTML file, or modify the "hello vue" file to look like this:


<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>

    <div id="app">
      <user-list></user-list>
    </div>

    <script type="text/javascript">

      let userList = Vue.component('user-list', {
      template : '<div>I am a component</div>'

      });

       let app = new Vue({
           el : "#app"

       });

    </script>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

What we have done is create a Vue component, named it “user-list” and then within our HTML, we have used user-list like a normal HTML tag. This is how you output your component to the front end.
You can see the template attribute in the Vue component definition, this specifies the HTML tags that will be output by the component when mounted. Take note, that a Vue component can only have one root element.
That’s all there is to creating a basic component in Vue.

Our Component

Although this works, it is not very useful as it does not demonstrate the power and reusability of components. Let’s extend this component further by defining props.

Props and Components

Each Vue component lives in a scope of its own and should not access data from the outside.
Props give us a means of passing data from a parent component (outside), to a child component. In our case, we will be passing data from app to the userList component. But before we can do this, we have to explicitly specify the props we are expecting in our user-list component. Add another attribute to the user-list component, call it props this will be an array of all the props we are expecting to be passed to the user-list component. Let the content of the props attribute be ['users'] While we are at it, let’s modify the template attribute, and remove all contents of the div replacing them with {{users}}.

Also in the main HTML file, let’s add a new attribute called “users” to the <user-list> tag, and set the value to users="list of users".

Right now, our app’s source code should look somewhat like this:


<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>

    <div id="app">
      <user-list users="list of users"></user-list>
    </div>

    <script type="text/javascript">

      let userList = Vue.component('userList', {
      template : '<div>{{users}}</div>',
      props: ['users']

      });

       let app = new Vue({
           el : "#app"

       });

    </script>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

If everything works correctly, the output should be this:
Displaying data passed as Prop

As we can see, our component has become a little smarter, data can now be passed from the parent to it, using users attribute.

This does not mean that only strings can be passed as props, variables can be passed as well, using the v-bind Vue attribute. Let’s extend things a little further. In our main Vue app, we will define a data attribute and pass in the variable which will be used by the Vue component. The data attribute will now be this:


         data(){
            return{
              allUsers : [
                {
                  name : 'John Doe',
                  about : 'Really nice guy'
                },
                {
                  name : 'Jane Dean',
                  about: 'Loves eggs'
                },
                {
                  name : 'Clark Kent',
                  about: 'Not your everyday reporter'
                }
              ]
            }
           }
Enter fullscreen mode Exit fullscreen mode

This basically just returned an array of three objects with two keys each, name and about.
To pass our newly defined list of users to the component, we simply add the v-bind:users attribute to the component, and pass the name of the array to it, hence we have <user-list v-bind:users="allUsers"></user-list> . The v-bind: prefix tells Vue that we want to dynamically bind the users props to a variable, and not pass in a string literal directly.

Right now, we have this as our app source code:


<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
</head>
<body>

    <div id="app">
      <user-list v-bind:users="allUsers"></user-list>
    </div>

    <script type="text/javascript">

      let userList = Vue.component('userList', {
      template : '<div>{{users}}</div>',
      props: ['users']

      });

       let app = new Vue({
           el : "#app",

           data(){
            return{
              allUsers : [
                {
                  name : 'John Doe',
                  about : 'Really nice guy'
                },
                {
                  name : 'Jane Dean',
                  about: 'Loves eggs'
                },
                {
                  name : 'Clark Kent',
                  about: 'Not your everyday reporter'
                }
              ]
            }
           }

       });

    </script>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Remember we said earlier that we want our component to be able to list all users passed to it. To do this, we need to perform List Rendering, using the v-for directive. The directive is used to render a list of items based on an array.
The syntax is like this:

<li v-for="item in items"></li> 
Enter fullscreen mode Exit fullscreen mode

Here, items is an array and item is an alias for the current array item being iterated upon. Armed with the knowledge of list rendering, let’s extend our user-list component to iterate over all users. To do this, we replace our template with this:


template : `
        <ul>
          <li v-for="user in users">
            {{user.name}}
          </li>
        </ul>
`,

Enter fullscreen mode Exit fullscreen mode

In case you are not familiar, the back-ticks are called template literals in modern JavaScript, they allow us to have multi-line statements, like the one above. You can learn more about template literals here

What we have done above is to define a base ul element and then, iterate through, and dynamically create all the <li> tags in the element using the v-for list rendering directive. If you run the code we currently have, this should be your output:

Looping through the user object

Handling the Click Event

Because we want our components to be re-usable, we will not handle the click event inside the component, instead, we will return the event to the parent component, which will use passed in the payload to perform any action it pleases. The advantage of this is that we can use the same component for many different purposes.

We will do this by making the user-list component emit an event when an item is clicked, and we will be handling this event on the parent component.

Let’s add an onclick listener to the <li> element, we do this in Vue by adding the @click attribute. This click event will call an internal method, and pass the user’s about attribute to the method.


<li v-for="user in users" @click="emitClicked(user.about)">
  {{user.name}}
</li>

Enter fullscreen mode Exit fullscreen mode

You can see above, that there is a method passed to the click handler, called the emitClicked method, we will define this method by adding the methods attribute to our Vue component.


methods : {
  emitClicked(data){
      this.$emit('item-clicked',data)
}
Enter fullscreen mode Exit fullscreen mode

This method emits an event, with a payload, which the parent can listen for, and use for operations.

Listening for Events

The easiest way to listen for an event in a parent component is by using the v-on attribute. Remember in the child component, we emitted an item-clicked event, so we can easily listen for the event by adding the v-on:item-clicked attribute to the <user-list> HTML tag.

<user-list v-bind:users="allUsers" v-on:item-clicked="alertData"></user-list>
Enter fullscreen mode Exit fullscreen mode

From the code above, we can see that there is a new method called alertData, This method is what handles the payload(data) passed out from the child component when it emitted the event.

We will define the alertData method inside the main component by adding the methods attribute as well.


 methods: 
{
  alertData(data)
  {
    alert(data)
  }
}
Enter fullscreen mode Exit fullscreen mode

This method simply uses the native alert method to display the data that has been passed from the child component.

Right Now our entire code should look like this:


    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js'></script>
    </head>
    <body>

        <div id="app">
          <user-list v-bind:users="allUsers" v-on:item-clicked="alertData"></user-list>
        </div>

        <script type="text/javascript">

          let userList = Vue.component('userList', {
          template : `
            <ul>
              <li v-for="user in users" @click="emitClicked(user.about)">
                {{user.name}}
              </li>
            </ul>
          `,

          props: ['users'],

          methods : {
            emitClicked(data){

              this.$emit('item-clicked',data)

            }
          }

          });

           let app = new Vue({
               el : "#app",

               data(){
                return{
                  allUsers : [
                    {
                      name : 'John Doe',
                      about : 'Really nice guy'
                    },
                    {
                      name : 'Jane Dean',
                      about: 'Loves eggs'
                    },
                    {
                      name : 'Clark Kent',
                      about: 'Not your everyday reporter'
                    }
                  ]
                }
               },

               methods: 
               {
                  alertData(data)
                  {
                    alert(data)
                  }
               }

           });

        </script>

    </body>
    </html>
Enter fullscreen mode Exit fullscreen mode

Our Final Application

The re-usability of this component lies in the fact that the v-on:item-clicked can accept different methods, and produce different outputs, hence, the user-list component can be reused severally across the application.

Conclusion

Components can be very useful in separating concerns for our front-end application and breaking it up into smaller logical bits. As a rule of thumb, components should perform a singular function, to enable maximum re-usability. In this article, we have been able to explore how to create a component, and pass data between the component and its parent.

Top comments (0)