We have learned how to create an API service and fetch data from the backend. Now, it’s time to display that data to a user and for that, we need to create a component. As we mentioned in Part 1 of this series, the Vue.js components consist of three parts: a template, a script and a style.
After we create a component, we have various ways to use it. We can register it globally to use it in any other component. Otherwise, we can internally register it inside a single component and it will be available only in that component.
We can register a component in both ways by specifying a custom tag for that component and the component itself. When we use that custom tag somewhere in our code, that tag will be replaced with the template from that component. Another way of using component is actually rendering component when the route for that component is matched.
All that being said, let’s create a component to display all the owner entities.
For the main page of this series, you can visit Vue.js Series.
To download the source code for this part, visit Creating Components and Data Display Source Code.
This post is divided into several sections:
- Creating a Component
- Fetching Data From the Server
- Displaying Data in a Template
- Interpolation and v-for
- Conclusion
Creating a Component
Let’s navigate to the src/components
directory and create a new directory and name it owner
. Then, we are going to create the OwnerList.component.vue
file in that directory. For now, we are going to put some dummy text in the component template. Next, we are going to make a route for that component and check if everything is OK.
Let’s create the OwnerList
component:
<template> <div> <p>This is owner-list component page.</p> </div> </template> <script> export default { name: 'OwnerList' }; </script>
Now, we are going to edit the
src/router/index.js
file and add the new route for this component:routes: [ { path: '/', name: 'Home', component: Home }, { path: '/owner/list', name: 'OwnerList', component: OwnerList }, { path: '*', name: 'NotFound', component: NotFound } ]
Finally, we are going to edit the
Navbar.vue
component and change the Owner Actions
link to point to our new component.
Let’s modify link in the Navbar.vue
component:
<b-navbar-nav> <b-nav-item :to="{ name: 'OwnerList' }">Owner Actions</b-nav-item> <b-nav-item href="#">Owner Actions</b-nav-item> </b-navbar-nav>
To inspect the results, let’s start our application by typing the
npm run dev
command inside a terminal window, and navigate to the Owner Actions menu item:
Great!
Now, let’s modify our component to fetch owners from the backend, store it in the variable inside a component and
render that data in a template.
Fetching Data From the Server
It’s important to say that every Vue component is actually a new Vue instance.
But what does that mean?
That means that every component has its own isolated scope. If we use the same component at different places we are actually instantiating it multiple times, and each instance would have its own data.
So, to summarize.
Vue components are reusable Vue instances.
Because Vue.js creates a Vue instance from our .vue
files, we must follow some naming conventions in our script tag. For example, where we put components data, methods, lifecycle hooks, etc.
Let’s create a variable where we are going to store our owners fetched from the backend:
<template> <div> <p>This is owner-list component page.</p> </div> </template> <script> export default { name: 'OwnerList', data() { return { owners: [] }; } }; </script>
There is the
data()
function which returns a JSON object with keys and values. That’s how we declare data for our component. We declare the owners
variable and set it’s initial value to an empty array. To access this variable in our code, we are going to use the this.owners
expression and the this
keyword will point to the Vue instance of this component.
As a continuation, we are going to implement the created()
lifecycle hook in which we are going to call our API service created in the previous part of this series. As a result, we are going to store data in the owners
variable by using this.owners
expression:
<script> import OwnerService from '@/api-services/owner.service'; export default { name: 'OwnerList', data() { return { owners: [] }; }, created() { OwnerService.getAll().then((response) => { this.owners = response.data; }); } }; </script>
Excellent.
Displaying Data in a Template
Now that we have our data, it’s time to change a template part of our component to actually display that data.
So, we are going to do exactly that:
<template> <div> <b-row> <b-col md="2" offset-md="10"> <a href="#">Create owner</a> </b-col> </b-row> <br> <b-row> <b-col md="12"> <div class="table-responsive"> <table class="table table-striped"> <thead> <tr> <th>Owner name</th> <th>Owner address</th> <th>Date of birth</th> <th>Details</th> <th>Update</th> <th>Delete</th> </tr> </thead> <tbody> <tr v-for="owner in owners" :key="owner.id"> <td>{{ owner.name }}</td> <td>{{ owner.address }}</td> <td>{{ owner.dateOfBirth }}</td> <td> <b-button variant="default">Details</b-button> </td> <td> <b-button variant="success">Update</b-button> </td> <td> <b-button variant="danger">Delete</b-button> </td> </tr> </tbody> </table> </div> </b-col> </b-row> </div> </template>
In case you wonder why we haven’t used the
table
component from the bootstrap-vue
package, the answer is because we want to explain the v-for
directive and how to use it to iterate through data and render some HTML multiple times. The table
component from the bootstrap-vue
package does all that under the hood.
Interpolation and v-for
Let’s again take a look at this code snippet:
<tr v-for="owner in owners" :key="owner.id"> <td>{{ owner.name }}</td> <td>{{ owner.address }}</td> <td>{{ owner.dateOfBirth }}</td> <td> <b-button variant="default">Update</b-button> </td> <td> <b-button variant="success">Update</b-button> </td> <td> <b-button variant="danger">Delete</b-button> </td> </tr>
We can see the
v-for
directive inside the tr
tag. That means that a tr
tag with its children tags will be rendered for every owner in owners
and owners
is the variable from our data()
function. We can also see the :key
prop. It’s called a data binding and we will talk more about that in the next part of this series. For now, it’s only important to remember that the v-for directive needs a unique key
for every element. When something changes in the owners
array, Vue.js will automatically update our table with the new value, and Vue.js knows which element to update due to key
property.
You might have noticed curly braces as well. This is an interpolation and all it does is displaying some dynamic data in our template. In this case, the v-for
directive creates the local variable owner
which is only accessible in a tr
element. It contains a single owner
from the owners
array and we can use the {{ owner.someProperty }}
expression to actually render it in our template. We can also access any variable from our data()
function.
Let’s open a terminal and execute the npm run dev
command. After starting the application, let’s click on Owner Actions
and inspect the result:
Conclusion
As you can see, we have implemented all that we have learned so far including components, routes and API services.
On the other hand, we’ve also we learned some new concepts.
By reading this post you’ve learned:
- How to execute an HTTP request
- How to display data from the backend in the component
- The way of render DOM element multiple times
- And how to interpolate data from the component
In the next part of the series, we are going to show how the parent component can pass some data to the child component and vice versa. Also, we are going to show how to listen to JavaScript events and how to create and listen to custom events.
You must be careful importing this component
I have a question concerning the owner object properties. I the Asp.Net Core project the owner class is defined like this:
public class
Owner : IEntity
{
[Key]
[Column(“OwnerId”)]
public Guid Id { get; set; }
[Required(ErrorMessage = “Name is required”)]
[StringLength(60, ErrorMessage = “Name can’t be longer than 60 characters”)]
public string Name { get; set; }
[Required(ErrorMessage = “Date of birth is required”)]
public DateTime DateOfBirth { get; set; }
[Required(ErrorMessage = “Address is required”)]
[StringLength(100, ErrorMessage = “Address can not be loner then 100 characters”)]
public string Address { get; set; }
}
In the we are accessing owner.name, owner.address, etc. as per JS naming conventions. In other projects I added [JsonProperty(PropertyName = “name”)] for an angular.js app to consume. Since this WebAPI uses the ShapedEntity class this property is not being used. I like the ShapedEntity process but wanted to know if you knew of a way to do this.
Thanks. I am really enjoying this series.
Ray