Students predict what a made-up tag shows, make cards from a list with a component and props, find a prop passed without its colon, add a medal to every card and a player to the data, and make pet cards.
Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.
Predict and Run 10 min · Investigate 15 min · Modify 10 min · Make 20 min
Read the unit primer first. app.component("player-card", { props: [...], template: ... }) registers a new tag; every <player-card> on the page becomes a copy of the template. Props are its inputs: the tag that uses it hands them in. :wins="p.wins" (with a colon, short for v-bind:) passes the value of p.wins; wins="p.wins" passes the words, which is the planted bug.
Two rules come from writing the page straight into HTML, without a build step: component names need a dash, and their tags need a separate closing tag (<player-card></player-card>, not <player-card />). The template is a JavaScript string between back-ticks, so it can span lines.
Props flow one way: a card should not change its own props (Vue warns if it tries). Changing data happens in the parent; sending messages up from a component (emit) is left out of this course.
Students try to read the players list inside the component. Ask "what has this card been given?" and point to props.
| What you will see | A question to ask | The fix |
|---|---|---|
| Cards show words like p.name. | Is there a colon before the prop? | :name="p.name" passes the value. |
| Nothing shows, and the console warns about failing to resolve a component. | Is app.component before app.mount, with the same name as the tag? | Register it before mount; the tag and the name must match, dash included. |
| A prop is blank on every card. | Is it in the props list? | props: ["name", "kind"] |
One possible solution for each task. Other correct programs are fine.
<div id="app">
<h1>Chess ladder</h1>
<player-card v-for="p in players" :name="p.name" :wins="p.wins"></player-card>
</div>
<script src="vue.js"></script>
<script>
const { createApp, ref } = Vue;
const app = createApp({
setup() {
const players = ref([
{ name: "Ada", wins: 5 },
{ name: "Sam", wins: 4 },
{ name: "Lin", wins: 2 }
]);
return { players };
}
});
app.component("player-card", {
props: ["name", "wins"],
template: `
<div style="border: 2px solid teal; padding: 8px; margin: 8px 0;">
<h2>{{ name }}</h2>
<p>Wins: {{ wins }}</p>
<p v-if="wins >= 5">🏅 Top player</p>
</div>`
});
app.mount("#app");
</script>
<div id="app">
<h1>Chess ladder</h1>
<player-card v-for="p in players" :name="p.name" :wins="p.wins"></player-card>
</div>
<script src="vue.js"></script>
<script>
const { createApp, ref } = Vue;
const app = createApp({
setup() {
const players = ref([
{ name: "Ada", wins: 5 },
{ name: "Sam", wins: 4 },
{ name: "Lin", wins: 2 },
{ name: "Kai", wins: 3 }
]);
return { players };
}
});
app.component("player-card", {
props: ["name", "wins"],
template: `
<div style="border: 2px solid teal; padding: 8px; margin: 8px 0;">
<h2>{{ name }}</h2>
<p>Wins: {{ wins }}</p>
</div>`
});
app.mount("#app");
</script>
<div id="app">
<h1>Pets at our school</h1>
<pet-card v-for="p in pets" :name="p.name" :kind="p.kind"></pet-card>
</div>
<script src="vue.js"></script>
<script>
const { createApp, ref } = Vue;
const app = createApp({
setup() {
const pets = ref([
{ name: "Biscuit", kind: "guinea pig" },
{ name: "Nemo", kind: "goldfish" },
{ name: "Pepper", kind: "rabbit" }
]);
return { pets };
}
});
app.component("pet-card", {
props: ["name", "kind"],
template: `
<div style="border: 2px dashed orange; padding: 8px; margin: 8px 0;">
<h2>{{ name }}</h2>
<p>A {{ kind }}</p>
</div>`
});
app.mount("#app");
</script>
Stretch: Give player-card a computed of its own (setup(props) { … }) that shows a rating from the wins. Make the cards sit in a row with Flexbox.
Support: Give the pet-card component written out; students add the v-for tag only.
What is the difference between wins="p.wins" and :wins="p.wins"?
Without the colon the card is given the words p.wins; with the colon it is given the value of p.wins.
Next: the final challenge, a to-do app built in milestones, with an optional lesson that builds the same app in three frameworks. Class idea: open a shopping site and count the cards made from one component.