Templating
Setup
I’ve created a git repo with the base application. Inside that repo, I’ve set up a page with the start of a session list for the CodeMash conference. The data is currently hard-coded, giving three sample sessions to show how they should look. Our job is to convert that hard-coded data into a vue template that reads data from the API.
First, we’ll get the code up and running. Execute the following commands:
git clone
https://github.com/akatakritos/codemash-schedule-vue.git
- this gets the source code from GitHub
cd codemash-schedule-vue
- change the directory into the code we just downloaded
git checkout 1-templating
to switch to the first exercise branch
npm install
- install all the libraries needed to build and run the application
npm run dev
- start the application
You should now be able to open the site in your web browser. You can copy-paste the link from your terminal or press o
, then Enter
to have Vite open it.
Data overview
In the application, we have a list of conference sessions. Each “card” shows:
level
- whether the talk is meant for introductory, intermediate, or advanced audiences
title
speakers
- note that sessions might have multiple speakers
excerpt
- a short snippet of the session's full abstract. This view only shows a truncated version of the description
day
,startTime
, andendTime
that make up the schedule details
This data is served from a fake API hosted in the codebase. The public
directory contains an api
folder with many .json
files that comprise the data. The full session list driving this page is in public/api/sessions/index.json
. The starter kit includes some code to load and log it to the console. We’ll work more closely with the API in a later module.
Open src/components/SessionList.vue
in your editor. Notice that the list of sessions is loaded and stored into a variable called sessions
. We’ll use that variable in our templates to display real data.
Updating the Count
Let’s start with an easy one. The application will eventually support filters, but for now, there is a line that says, “Showing 3 of 3 talks.” Once we have filters, this would show how many sessions matched the user’s current search, for example, “Showing 17 of 212 talks”. Let's update this so that it is driven from the real session count instead of a hardcoded 3
.
In src/components/SessionList.vue
find the line of code that outputs the text “Showing 3 of 3 talks”. We want to replace the 3
’s with the current length of the sessions
variable.
Make the following changes:
<!-- we're going to add filters in a later module that will update these counts -->
- <p>Showing 3 of 3 talks</p>
+ <p>Showing {{ sessions.length }} of {{ sessions.length }} talks</p>
Save your changes and switch back to your browser. It should now say “Showing 211 of 211 talks”.
Congratulations, you’re officially a Vue programmer!

Implement the List
Right now the screen is showing three hard-coded sessions at three different skill levels. The first thing we can do is get it start showing all 211 talks. Vue uses the v-for
directive to control repetition of a template across each item in a list.
Find the markup for the first card in the list, after the <!-- introductory and overview -->
comment. Apply the v-for
and :key
bindings as follows.
<!-- introductory and overview -->
- <div class="card">
+ <div class="card" v-for="session in sessions" :key="session.id">
<div class="card-body">
After saving and switching back to the browser you should see that you have the first card duplicated 211 times! Progress! We still have to update the template to read the title
and excerpt
and other data from the real list.
:key
attribute when using v-for
. This is an important performance optimization that helps Vue efficiently modify a list of elements when the data changes.
Making the cards show real data
We’ll start with updating the template to output the text values.
Open public/api/sessions/index.json
to see the properties that are available on each session. Think about which spot in the UI corresponds to each property. For this card we’ll need
title
speakers
level
excerpt
day
startTime
endTime
Since the parent div
for the card uses v-for="session in sessions
, it’s child elements will have access to the session
variable which is the current item in the loop. This is very similar to how a foreach
or for
loop works in C# and Java.
We can read properties from that variable and output them to the screen, for example {{ session.title }}
will show the title on the screen.
Implementing the template
For every piece of hard-coded data, replace the text with the corresponding property. For example replace Introductory and overview
with {{ session.level }}
. Don’t worry about getting the background color on the skill level badge right, we’ll tackle that next.
Note that speakers
is an array of strings because a conference talk can have multiple speakers. We need to convert that array into a single, comma separated string. Luckily javascript has a method on Array
to do that: join
. Using session.speakers.join(', ')
we can convert the list of speaker names into a comma-separated string. Vue will let us call it from the template inside the double curly braces just like any other javascript expression. No magic here!
The full set of changes so far should look like this:
<div class="card-body">
- <span class="badge bg-success">Introductory and overview</span>
- <h5 class="card-title">Build a Modern Single Page Application with Vue</h5>
- <h6 class="card-subtitle mb-2 text-body-secondary">Matt Burke</h6>
- <p class="card-text">
- Vue offers developers a way to build ambitious front-end applications with powerful reactive programming
- patterns and an intuitive HTML-based templating language. This workshop will give you a jumping-off point
- for large front-end applications using Vue with blazing-fast dev tools like esbuild,...
- </p>
+ <span class="badge bg-success">{{ session.level }}</span>
+ <h5 class="card-title">{{ session.title }}</h5>
+ <h6 class="card-subtitle mb-2 text-body-secondary">{{ session.speakers.join(', ') }}</h6>
+ <p class="card-text">{{ session.excerpt }}</p>
<div class="footer pt-2">
- <span> Tuesday 8:00 - 12:00</span>
+ <span> {{ session.day }} {{ session.startTime }} - {{ session.endTime }}</span>
<a href="" class="btn btn-primary">Details</a>
</div>
</div>
Using the class binding
If you look at it now, we have all the data, but the color of the level is not changing depending on if its Advanced
, Intermediate
, or Introductory and overview
.
Lets look more closely at the final two hard-coded sample talks that are now all the way at the bottom. Carefully considering them, we can see that there is a difference in the class
attribute on the span
showing the skill level text:
- If the skill level is
Introductory and overview
we haveclass="badge bg-success"
- If the skill level is
Intermediate
we haveclass="badge bg-warning"
- If the skill level is
Advanved
we haveclass="badge bg-danger"
In short, each has the badge
class and a different bg-*
class depending on level. We could tackle this with v-if
and v-else-if
, but a better way to do dynamic CSS classes is to use Vue’s :class
binding. This binding can accept an object and any property on that object that evaluates to true
will apply the property name as a css class.
In other words, we can produce an object like this and Vue will know to apply the right bg-*
class to the element.
{
'bg-success': session.level === 'Introductory and overview',
'bg-warning': session.level === 'Intermediate',
'bg-danger': session.level === 'Advanced'
}
-
) in them if they are wrapped in quotes.{
'bg-success': true,
'bg-warning': false,
'bg-danger': false
}
If the object evaluated to something like this, any property with a true
value will be turned into an addition to the element’s class
attribute.
The badge
class is static and should be there always, but we can also add a dynamic class binding through :class
<div class="card-body">
- <span class="badge bg-success">Introductory and overview</span>
+ <span class="badge" :class="{
+ 'bg-success': session.level === 'Introductory and overview',
+ 'bg-warning': session.level === 'Intermediate',
+ 'bg-danger': session.level === 'Advanced'
+ }">{{ session.level }}</span>
<h5 class="card-title">{{ session.title }}</h5>
Now we can delete the remaining two examples from the original markup
Conditionally show the empty message
The last piece of dynamic content is a message that is supposed to show when there are no talks matching the user’s search. In the template, it’s currently commented out with an HTML comment (<!— —>
). We need to uncomment it, and then use the v-if
binding to only render it when there are no sessions
<!-- show this if there are no sessions -->
- <!--<p>No sessions found</p>-->
+ <p v-if="sessions.length === 0">No sessions found</p>
</div>
If you open your browser now, you’d still not see it, because we don’t have filters hooked up yet, and there are 211 talks to show. If you want to see it, comment out the assignment to session.value
in the onMounted
hook near the top of the file:
// sessions.value = data
Recap
- You learned you to display text from javascript variables using the
{{ }}
output bindings
- You learned how to render a template for each item in a list using the
v-for
directive
- You learned how to conditionally apply CSS classes using the
:class
binding
- You learned how to conditionally render part of a template using the
v-if
binding
Further Reading
Bonus
- change
v-if
tov-else
: what happens?
- Try changing the skill level badge to use
v-if
,v-else-if
andv-else
instead of the:class
binding
- try misspelling some of the property names: what happens?
- As a conference attendee, I want to see how each talk is categorized by its tags.
- Choose a bootstrap component and implement it in the card to show the list of tags each session has.