Make one tag for each item in a list with v-for, show a tag only when it is needed with v-if, and watch both keep up as the list changes.
A chat, a playlist and a search page are all lists that change. v-for keeps the page in step with the list.
In the DOM course, a list on the page took a loop, createElement and append, and the page changed only when you made or removed elements. In Vue you write the tag once:
<li v-for="name in players">{{ name }}</li>
v-for makes one <li> for each item in players, with name standing for the item each time. Change the list, and Vue adds or removes <li> tags to match.
v-if shows a tag only while something is true:
<p v-if="players.length === 0">No players yet.</p>
Make your prediction first. Help opens once you've locked it in.
<div id="app">
<ul>
<li v-for="name in players">{{ name }}</li>
</ul>
<button @click="players.push('Kai')">Add Kai</button>
</div>
<script src="vue.js"></script>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const players = ref(["Ada", "Sam", "Lin"]);
return { players };
}
}).mount("#app");
</script>
In the DOM course, pushing to an array did not change the page. What about here?
Press Run. Add Kai, then remove players until none are left, and watch the message.
<div id="app">
<h1>Chess team</h1>
<ul>
<li v-for="name in players">{{ name }}</li>
</ul>
<p v-if="players.length === 0">No players yet.</p>
<button @click="players.push('Kai')">Add Kai</button>
<button @click="players.pop()">Remove the last</button>
</div>
<script src="vue.js"></script>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const players = ref(["Ada", "Sam", "Lin"]);
return { players };
}
}).mount("#app");
</script>
<div id="app">
<h1>Chess team</h1>
<ul>
<li v-for="name in players">{{ name }}</li>
</ul>
<p v-if="players.length === 0">No players yet.</p>
<button @click="players.push('Kai')">Add Kai</button>
<button @click="players.pop()">Remove the last</button>
</div>
<script src="vue.js"></script>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const players = ref(["Ada", "Sam", "Lin"]);
return { players };
}
}).mount("#app");
</script>
Count the tags.
v-for, v-if and the item.
Three lists instead of one.
Start with Ada, Sam and Lin. Fill in the page after each click.
| after | li tags on the page | No players yet shows? |
|---|---|---|
| the start | 3 | no |
| Add Kai | ||
| Remove the last, four times | ||
| Add Kai |
Match each part with what it does.
The page shows three separate lists, each with one name. There is no error. Click the line that is wrong.
One button, an empty list.
Emptying the list means giving players a new, empty list.
<button @click="players = []">Clear</button>

A second v-if.
A second v-if can look for a different number.
<p v-if="players.length >= 5">Team full!</p>

Add a Clear button that empties the list.
This ticks when your page has all of the above.
Show Team full! when there are 5 or more players.
This ticks when your page has all of the above.
Show the songs as a list with v-for, a message with v-if when there are none, and buttons that add a song and remove one (push, pop, or shift, which takes the first).
Show the songs with v-for, a message with v-if when there are none, and buttons that change the list.
This ticks when your page has all of the above.
Next: events and inputs: functions on clicks, and boxes joined to data.
Students predict that pushing to a list adds a tag, trace the page as the list changes, find v-for on the wrong tag, add a Clear button and a Team full message, and make a playlist. About 50 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
Read the unit primer first. v-for="name in players" on a tag makes one copy of that tag per item; inside it, name is the item for that copy. v-if="…" adds the tag while the condition is true and removes it otherwise. Both are attributes on the tag they control, which is why the planted bug (v-for on the ul) makes three lists.
This reverses the DOM course's lesson on lists, where changing an array did not change the page ("list-is-live"). In Vue it does, because the list is a ref. Say so explicitly to students who did the DOM course; it is a good moment to name what Vue is doing for them.
Real Vue code adds :key to v-for tags (:key="name") so Vue can tell items apart when they move; it does not change what students see here, so the course leaves it to the stretch. players = [] inside @click works because the page unwraps refs for you (lesson 3 shows the script side).
Students put v-for on the container because "it's the list". Ask "which tag do you want more of?" and let them move it themselves.
Stretch: Add :key="song" to the v-for. Number the items with v-for="(song, i) in songs" and {{ i + 1 }}. Add v-else after a v-if.
Support: Give the ul with v-for already written; students add only the v-if message.
Next lesson: functions for events and v-model for inputs, so the list can take any name. Class idea: find three lists on a website and say what each item's data would be.