curriculum/challenges/english/blocks/lab-football-team-cards/66e7ee20b79186306fc12da5.md
In this lab, you will build a set of football team cards. The user should be able to use the dropdown menu and filter between the different players based on their positions.
Objective: Fulfill the user stories below and get all the tests to pass to complete the lab.
User Stories:
You should create a footballTeam object with the following properties: team, year, headCoach, players.
The team property should contain the name of the team as a string.
The year property should contain the year as a number.
The headCoach property should contain the name of the head coach as a string.
The players property should be an array containing at least four elements.
Each element in the players array should be an object with properties name, position, isCaptain.
The name property should contain the name of the player as a string.
The position property should have one of the following values: "forward", "midfielder", "defender", or "goalkeeper".
The isCaptain property should have value of a boolean. One of the players should have their isCaptain property set to true.
You should display the headCoach, team and year values on the page. These values should be displayed in the HTML elements with the id values of head-coach, team and year.
You should display the players data on the page inside the #player-cards element, each player should be displayed in a div with class of player-card, and nested in it, an h2 containing the name of the player, and (Captain) in case of the player being captain, and a p containing Position: and the position of the player.
Here is an example of how the HTML should look like:
<div class="player-card">
<h2>Sergio Batista</h2>
<p>Position: midfielder</p>
</div>
<div class="player-card">
<h2>(Captain) Diego Maradona</h2>
<p>Position: midfielder</p>
</div>
When the dropdown menu is used to select one of the positions, only the .player-card elements for players of that position should be present. If the "All Players" option is selected, then all of the players should display on the page.
You should have a footballTeam variable.
assert.exists(footballTeam);
The footballTeam variable should be an object with four properties: team, year, headCoach and players.
assert.isObject(footballTeam);
assert.containsAllKeys(footballTeam, ['team', 'year', 'headCoach', 'players']);
The team property should be a string.
assert.isString(footballTeam.team);
The year property should be a number.
assert.isNumber(footballTeam.year);
The headCoach property should be a string.
assert.isString(footballTeam.headCoach);
The players property should be an array of at least four objects, each object should have the keys name, position, isCaptain.
assert.isArray(footballTeam.players);
assert.isAtLeast(footballTeam.players.length, 4);
footballTeam.players.forEach(player => {
assert.isObject(player);
assert.containsAllKeys(player, ['name', 'position', 'isCaptain']);
})
The name property should have value of a string.
footballTeam.players.forEach(({name}) => assert.isString(name));
The position property should have one of values "forward", "midfielder", "defender", or "goalkeeper".
footballTeam.players.forEach(({position}) => {
assert.isString(position);
assert.oneOf(position, ["forward", "midfielder", "defender", "goalkeeper"]);
});
The isCaptain property should have value of a boolean, and there should be only one captain.
footballTeam.players.forEach(({isCaptain}) => assert.isBoolean(isCaptain));
const listOfCaptains = footballTeam.players.filter(({isCaptain}) => isCaptain);
assert.lengthOf(listOfCaptains, 1);
You should display the headCoach, team and year values from the footballTeam object in the HTML elements with the id values of head-coach, team and year.
const teamElement = document.querySelector('.team-stats #team');
const yearElement = document.querySelector('.team-stats #year');
const headCoachElement = document.querySelector('.team-stats #head-coach');
assert.equal(teamElement?.innerText.trim(), footballTeam.team);
assert.equal(yearElement?.innerText.trim(), footballTeam.year);
assert.equal(headCoachElement?.innerText.trim(), footballTeam.headCoach);
When the option All Players is selected, all players should be present within #player-cards.
const select = document.querySelector('#players')
select.value = 'all';
select.dispatchEvent(new Event('change'))
const playerCards = document.querySelectorAll('.player-card');
const arrayFromPage = Array.from(playerCards).map(el => ({
name: el.querySelector('h2').innerText.replace('(Captain)', '').trim(),
position: el.querySelector('p').innerText.replace('Position:', '').trim(),
isCaptain: /Captain/.test(el.querySelector('h2').innerText)
}))
assert.sameDeepMembers(arrayFromPage, footballTeam.players);
When the option Position Forward is selected, only forward players should be present within #player-cards.
const forwards = footballTeam.players.filter(({position}) => position === 'forward')
const select = document.querySelector('#players')
select.value = 'forward';
select.dispatchEvent(new Event('change'))
const playerCards = document.querySelectorAll('.player-card');
const arrayFromPage = Array.from(playerCards).map(el => ({
name: el.querySelector('h2').innerText.replace('(Captain)', '').trim(),
position: el.querySelector('p').innerText.replace('Position:', '').trim(),
isCaptain: /Captain/.test(el.querySelector('h2').innerText)
}))
assert.sameDeepMembers(arrayFromPage, forwards);
When the option Position Midfielder is selected, only midfielder players should be present within #player-cards.
const midfielders = footballTeam.players.filter(({position}) => position === 'midfielder')
const select = document.querySelector('#players')
select.value = 'midfielder';
select.dispatchEvent(new Event('change'))
const playerCards = document.querySelectorAll('.player-card');
const arrayFromPage = Array.from(playerCards).map(el => ({
name: el.querySelector('h2').innerText.replace('(Captain)', '').trim(),
position: el.querySelector('p').innerText.replace('Position:', '').trim(),
isCaptain: /Captain/.test(el.querySelector('h2').innerText)
}))
assert.sameDeepMembers(arrayFromPage, midfielders);
When the option Position Defender is selected, only defender players should be present within #player-cards.
const defenders = footballTeam.players.filter(({position}) => position === 'defender')
const select = document.querySelector('#players')
select.value = 'defender';
select.dispatchEvent(new Event('change'))
const playerCards = document.querySelectorAll('.player-card');
const arrayFromPage = Array.from(playerCards).map(el => ({
name: el.querySelector('h2').innerText.replace('(Captain)', '').trim(),
position: el.querySelector('p').innerText.replace('Position:', '').trim(),
isCaptain: /Captain/.test(el.querySelector('h2').innerText)
}))
assert.sameDeepMembers(arrayFromPage, defenders);
When the option Position Goalkeeper is selected, only goalkeeper players should be present.
const goalkeepers = footballTeam.players.filter(({position}) => position === 'goalkeeper')
const select = document.querySelector('#players')
select.value = 'goalkeeper';
select.dispatchEvent(new Event('change'))
const playerCards = document.querySelectorAll('.player-card');
const arrayFromPage = Array.from(playerCards).map(el => ({
name: el.querySelector('h2').innerText.replace('(Captain)', '').trim(),
position: el.querySelector('p').innerText.replace('Position:', '').trim(),
isCaptain: /Captain/.test(el.querySelector('h2').innerText)
}))
assert.sameDeepMembers(arrayFromPage, goalkeepers);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>
Build a Set of Football Team Cards
</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1 class="title">Team stats</h1>
<main>
<div class="team-stats">
<p>Team: <span id="team"></span></p>
<p>Year: <span id="year"></span></p>
<p>Head coach: <span id="head-coach"></span></p>
</div>
<label class="options-label" for="players">Filter Teammates:</label>
<select name="players" id="players">
<option value="all">All Players</option>
<option value="forward">Position Forward</option>
<option value="midfielder">Position Midfielder</option>
<option value="defender">Position Defender</option>
<option value="goalkeeper">Position Goalkeeper</option>
</select>
<div class="cards" id="player-cards"></div>
</main>
<footer>© freeCodeCamp</footer>
<script src="./script.js"></script>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--dark-grey: #0a0a23;
--light-grey: #f5f6f7;
--white: #ffffff;
--black: #000;
}
body {
background-color: var(--dark-grey);
text-align: center;
padding: 10px;
}
.title,
.options-label,
.team-stats,
footer {
color: var(--white);
}
.title {
margin: 1.3rem 0;
}
.team-stats {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
font-size: 1.3rem;
margin: 1.2rem 0;
}
.options-label {
font-size: 1.2rem;
}
.cards {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.player-card {
background-color: var(--light-grey);
padding: 1.3rem;
margin: 1.2rem;
width: 300px;
border-radius: 15px;
}
@media (max-width: 768px) {
.team-stats {
flex-direction: column;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>
Build a Set of Football Team Cards
</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1 class="title">Team stats</h1>
<main>
<div class="team-stats">
<p>Team: <span id="team"></span></p>
<p>Year: <span id="year"></span></p>
<p>Head coach: <span id="head-coach"></span></p>
</div>
<label class="options-label" for="players">Filter Teammates:</label>
<select name="players" id="players">
<option value="all">All Players</option>
<option value="forward">Position Forward</option>
<option value="midfielder">Position Midfielder</option>
<option value="defender">Position Defender</option>
<option value="goalkeeper">Position Goalkeeper</option>
</select>
<div class="cards" id="player-cards"></div>
</main>
<footer>© freeCodeCamp</footer>
<script src="./script.js"></script>
</body>
</html>
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--dark-grey: #0a0a23;
--light-grey: #f5f6f7;
--white: #ffffff;
--black: #000;
}
body {
background-color: var(--dark-grey);
text-align: center;
padding: 10px;
}
.title,
.options-label,
.team-stats,
footer {
color: var(--white);
}
.title {
margin: 1.3rem 0;
}
.team-stats {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
font-size: 1.3rem;
margin: 1.2rem 0;
}
.options-label {
font-size: 1.2rem;
}
.cards {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.player-card {
background-color: var(--light-grey);
padding: 1.3rem;
margin: 1.2rem;
width: 300px;
border-radius: 15px;
}
@media (max-width: 768px) {
.team-stats {
flex-direction: column;
}
}
const teamName = document.getElementById("team");
const worldCupYear = document.getElementById("year");
const headCoach = document.getElementById("head-coach");
const playerCards = document.getElementById("player-cards");
const playersDropdownList = document.getElementById("players");
const footballTeam = {
team: "Argentina",
year: 1986,
headCoach: "Carlos Bilardo",
players: [
{
name: "Sergio Almirón",
position: "forward",
isCaptain: false,
},
{
name: "Sergio Batista",
position: "midfielder",
isCaptain: false,
},
{
name: "Ricardo Bochini",
position: "midfielder",
isCaptain: false,
},
{
name: "Claudio Borghi",
position: "midfielder",
isCaptain: false,
},
{
name: "José Luis Brown",
position: "defender",
isCaptain: false,
},
{
name: "Daniel Passarella",
position: "defender",
isCaptain: false,
},
{
name: "Jorge Burruchaga",
position: "forward",
isCaptain: false,
},
{
name: "Néstor Clausen",
position: "defender",
isCaptain: false,
},
{
name: "José Luis Cuciuffo",
position: "defender",
isCaptain: false,
},
{
name: "Diego Maradona",
position: "midfielder",
isCaptain: true,
},
{
name: "Jorge Valdano",
position: "forward",
isCaptain: false,
},
{
name: "Héctor Enrique",
position: "midfielder",
isCaptain: false,
},
{
name: "Oscar Garré",
position: "defender",
isCaptain: false,
},
{
name: "Ricardo Giusti",
position: "midfielder",
isCaptain: false,
},
{
name: "Luis Islas",
position: "goalkeeper",
isCaptain: false,
},
{
name: "Julio Olarticoechea",
position: "defender",
isCaptain: false,
},
{
name: "Pedro Pasculli",
position: "forward",
isCaptain: false,
},
{
name: "Nery Pumpido",
position: "goalkeeper",
isCaptain: false,
},
{
name: "Oscar Ruggeri",
position: "defender",
isCaptain: false,
},
{
name: "Carlos Tapia",
position: "midfielder",
isCaptain: false,
},
{
name: "Marcelo Trobbiani",
position: "midfielder",
isCaptain: false,
},
{
name: "Héctor Zelada",
position: "goalkeeper",
isCaptain: false,
},
],
};
const { sport, team, year, players } = footballTeam;
const coachName = footballTeam.headCoach;
teamName.textContent = team;
worldCupYear.textContent = year;
headCoach.textContent = coachName;
const setPlayerCards = (arr = players) => {
playerCards.innerHTML += arr
.map(
({ name, position, isCaptain }) =>
`
<div class="player-card">
<h2>${isCaptain ? "(Captain)" : ""} ${name}</h2>
<p>Position: ${position}</p>
</div>
`
)
.join("");
};
playersDropdownList.addEventListener("change", (e) => {
playerCards.innerHTML = "";
switch (e.target.value) {
case "forward":
setPlayerCards(players.filter((player) => player.position === "forward"));
break;
case "midfielder":
setPlayerCards(
players.filter((player) => player.position === "midfielder")
);
break;
case "defender":
setPlayerCards(
players.filter((player) => player.position === "defender")
);
break;
case "goalkeeper":
setPlayerCards(
players.filter((player) => player.position === "goalkeeper")
);
break;
default:
setPlayerCards();
}
});
setPlayerCards();