Final Fetch
Oh boy, I had to make today's code tinkering rather troublesome. I think it turned out decent though. I wanted to work with Fetch API and use it to load data from my Treehouse profile into a page. I decided to display it as if I was a character in the Famicom/NES game, Final Fantasy. Click the update info button to load information from my profile into the page.
Name
Job
Level ?
Experience Points
- Skill ??
- Skill ??
- Skill ??
- Skill ??
- Skill ??
- Badge
- Badge
- Badge
- Badge
- Badge
View the code:
HTML and JS
<section class="code-block">
<h1 id="name">Name</h1>
<h2 id="job"><img src="" id="img" alt="" width="16" height="16"/>Job</h2>
<h2 id="level">Level ?</h2>
<p id="exp"><span>Experience Points</span> <span id="expPoints"></span></p>
<div id="gridWrapper">
<div id="pointsWrapper">
<ul id="points">
<li>Skill <span>??</span></li>
<li>Skill <span>??</span></li>
<li>Skill <span>??</span></li>
<li>Skill <span>??</span></li>
<li>Skill <span>??</span></li>
</ul>
</div>
<div id="badgesWrapper">
<ul id="badges">
<li>Badge</li>
<li>Badge</li>
<li>Badge</li>
<li>Badge</li>
<li>Badge</li>
</ul>
</div>
</div>
<button id="importInfo">Update Info</button>
</section>
<script>
// ---------
// Variables
// ---------
const name = document.getElementById('name');
const job = document.getElementById('job');
const photo = document.getElementById('img');
const exp = document.getElementById('exp');
const expPoints = document.getElementById('expPoints');
const pointsWrap = document.getElementById('pointsWrapper');
const badgesWrap = document.getElementById('badgesWrapper');
const points = document.getElementById('points');
const badges = document.getElementById('badges');
const button = document.getElementById('importInfo');
// ---------
// Fetch Functions
// ---------
button.addEventListener('click', () => {
fetch('https://teamtreehouse.com/jeremycaudle85.json')
.then(response => response.json())
.then(data => updateInfo(data))
.catch(error => alert('Looks like there was a problem. Maybe the info the server comes from is having a problem. Try again another time. :)', error))
button.textContent = "Info Received";
button.toggleAttribute('disabled');
})
// ---------
// Helper Functions
// ---------
function updateInfo(data) {
console.log(data);
name.innerHTML = `<a href="${data.profile_url}">${data.name}</a>`;
name.setAttribute('class', 'updated');
job.innerHTML = `<img src="${data.gravatar_url}" id="img" alt="Photo of ${data.name}" width="16" height="16"/> Web Designer / Developer`;
job.setAttribute('class', 'updated');
level.textContent = 'Level 35';
level.setAttribute('class', 'updated');
expPoints.textContent = data.points.total;
exp.setAttribute('class', 'updated');
// Skills list
const pointsTreehouseSkills = Object.keys(data.points);
console.log(pointsTreehouseSkills);
const pointsTreehouseValues = Object.values(data.points);
console.log(pointsTreehouseValues);
let treeSkills = '';
for(let i = 0; i < pointsTreehouseSkills.length; i++) {
console.log('start loop');
let skillName = pointsTreehouseSkills[i];
let skillValue = pointsTreehouseValues[i];
treeSkills += `<li>${skillName} <span>${skillValue}</span></li>`;
};
points.innerHTML = treeSkills;
// Badges list
const badgesList = Object.values(data.badges);
console.log(badgesList);
let treeBadges = '';
for(let i = 0; i < badgesList.length; i++) {
console.log('start loop');
let badgeValue = badgesList[i].name;
console.log(badgeValue);
treeBadges += `<li><span>${badgeValue}</span></li>`;
};
badges.innerHTML = treeBadges;
pointsWrap.setAttribute('class', 'updated');
badgesWrap.setAttribute('class', 'updated');
}
</script>
CSS
/* Variables */
:root {
--bg-color: #111;
--bg-secondary: white;
--text-color: #232323;
--radius-main: 1rem;
}
@font-face {
font-family: "ThaleahFat";
src: url("https://jeremycaudle.com/retro-japanese-games/fonts/ThaleahFat.ttf") format("truetype");
/* Font Thaleah Fat by Tiny Worlds - Available at https://tinyworlds.itch.io/free-pixel-font-thaleah */
}
html { box-sizing: border-box; z-index: 0; }
html * { box-sizing: inherit; }
section.code-block {
background: var(--bg-color, #111);
max-width: 512px;
margin: 2rem auto;
padding: 1rem;
max-height: 480px;
}
section.code-block * {
font-family: "ThaleahFat", "Helvetica", "Arial", sans-serif;
font-weight: normal;
color: white;
}
section.code-block h1, section.code-block h2, section.code-block p, section.code-block div, section.code-block button {
font-size: 1.5rem;
background-color: rgb(48, 48, 48);
border: solid 2px white;
box-shadow: 0 0 0 2px gray, inset 0 0 0 2px gray;
border-radius: .25rem;
padding: .5rem;
margin: 0 0 .5rem 0;
transition: background-color .25s ease-out;
}
section.code-block ul {
list-style-type: none;
padding: 0;
margin: .5rem 0;
}
section.code-block ul li {
}
section.code-block ul li span {
text-align: right;
}
section.code-block button {
font-size: 1rem;
background-color: orange;
color:black;
cursor: pointer;
transition: all .125s ease-out;
margin: auto;
display: block;
}
section.code-block button:hover, section.code-block button:focus {
background-color: rgb(255, 175, 25);
border-color: black;
}
section.code-block .updated {
background-color: blue;
}
section.code-block button:disabled {
background-color: black;
border: gray;
box-shadow: none;
cursor: default;
color: white;
}
#points, #badges {
max-height: 135px;
overflow: auto;
scrollbar-color: transparent;
}
/* Float-based layout for older browsers */
#name, #job {
float: left;
margin-right:2%;
}
#level {
float:right;
}
#job {
width: 52%;
}
#name, #level {
width: 22%;
}
#exp {
float: none;
clear: both;
width: 80%;
margin: .5rem auto;
}
#exp span {text-align: left;}
#exp #expPoints {float: right;}
#expPoints::after {
content: "";
display: none;
height: 1px;
width: 1px;
float: none;
clear: both;
}
#pointsWrapper {
float:left;
width: 49%;
margin-right:2%
}
#badgesWrapper {
width: 49%;
float:right;
}
#importInfo {
float:none;
clear: both;
}
/* Support and media queries */
@supports (display:grid) {
#name, #job, #level, #exp, #exp #expPoints, #pointsWrapper, #badgesWrapper {
float:none;
width: auto;
}
section.code-block {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: repeat(3, min-content);
}
#name {
grid-column: 1 / 2;
grid-row: 1 / 2;
}
#job {
grid-column: 2 / 3;
grid-row: 1 / 2;
}
#exp {
grid-column: 1 / 4;
grid-row: 2 / 3;
width: 80%;
}
#importInfo {
grid-column: 2 / 3;
grid-row: 4 / 5;
}
section.code-block div#gridWrapper {
background: none;
border: none;
box-shadow: none;
margin: 0;
display: grid;
grid-template-columns: 1fr 1fr;
grid-column: 1 / 4;
grid-row: 3 / 4;
}
}