It’s almost impossible to build a Single Page App without a framework because of the complexity in each page. So the first thing we’re going to do is include a framework into the project.
For this project, we’re going to use the framework we built, Tiny.
// main.js
import Tiny from './Tiny/tiny.js'
We’ll begin by populating the Heroes List Page with heroes.
Building the structure
The Heroes List Page contains three major sections:
Notice the absolute url used for the the logo. We usually use absolute urls to find assets like images.
Next, we need to include the filter (which is in a sidebar) and the heroes list (which is the main content in this page). According to the HTML, both of these are in the <main> tag.
We’ll use placeholder text to replace the content for now.
Tiny({
// ...
template () {
return `
<!-- header -->
<main>
<div class="wrap">
<div class="site-title">
<h1>Heroes List</h1>
<p>Filter heroes based on these attributes</p>
</div>
<div class="sidebar-content">
<div class="sidebar flow"> Filters Go Here </div>
<div class="content"> Heroes Go Here </div>
</div>
</main>
`
}
})
Building the heroes list
To build the heroes list, we need to get a list of heroes from the Dota API. We can use afterMount to perform this initial fetch request.
After getting a list of heroes, we massage the data and get ready to populate it into the DOM.
Tiny({
// ...
afterMount () {
const dotaApi = 'https://api.opendota.com/api'
zlFetch(`${dotaApi}/constants/heroes`).then(response => {
const heroes = Object.values(response.body).map(hero => {
return {
name: hero.localized_name,
npcHeroName: hero.name.replace('npc_dota_hero_', ''),
attackType: hero.attack_type.toLowerCase(),
primaryAttribute: hero.primary_attr,
roles: hero.roles.map(role => role.toLowerCase()),
image: `https://api.opendota.com${hero.img}`
}
})
// Put this data into the DOM somehow
})
}
// ...
})
We need to re-render the component to add the Heroes into the DOM. The easiest way to do this is add the heroes into the components’ state.
Notice the there are two console.log statements? The first one happens on the first render, which is called before afterMount.
To render heroes, we need to loop through state.heroes. To loop through state.heroes, we must make sure it is an array. So we need to make sure state.heroes begins with an empty array (which signifies zero heroes).
Tiny({
// ...
state: {
heroes: []
}
// ...
})
We can now map through state.heroes — both on the initial render and after we obtained heroes from the Dota API. As we map through the heroes, we can populate the DOM with the necessary information.