List Views and Item Views
In many applications, you will need to represent an array of data to the user. Unlike a detail view, there is no way to ensure the right number of existing elements ready to accept data from each item in the array. This will actually require that we create TWO different view classes:
- List View - Responsible for managing an array of data
- Item View - Responsible for creating and managing an element to represent a single item from the array
Let's consider the following set of data:
[
{
"first": "Frank",
"last": "Underwood"
},
{
"first": "Zoe",
"last": "Barnes"
},
{
"first": "Peter",
"last": "Russo"
}
]
This will need to be turned into the following HTML:
<ul class="contacts">
<li class="contacts__item">
<span class="first">Underwood</span>, <span class="last">Frank</span>
</li>
<li class="contacts__item">
<span class="first">Barnes</span>, <span class="last">Zoe</span>
</li>
<li class="contacts__item">
<span class="first">Russo</span>, <span class="last">Peter</span>
</li>
</ul>
To start, we'll create the ContactView
class to manage an li
element for a contact object.
This will start with a constructor
that accepts the data needed, create the DOM element and blank shell for the data to fill in.
Then just like with a detail view, a render
function will be created to fill in this blank shell:
class ContactView {
constructor(data) {
this.data = data;
this.element = document.createElement(`li`);
this.element.classList.add(`contacts__item`);
this.element.innerHTML = `
<span class="first"></span>, <span class="last"></span>
`;
this.render();
}
render() {
this.element.querySelector(`.first`).innerText = this.data.first;
this.element.querySelector(`.last`).innerText = this.data.last;
}
}
This class alone won't be enough to represent our entire array of data and manage the full set of data. This is where a List View comes in to play: it will loop through the data and append it into an existing element in the DOM.
To start, we'll need a constructor
that accepts the element
we want to fill and the data
array we want to represent.
Then we'll create a render function that loops through the data and creates a new ContactView
for every item.
Finally, in the loop, we'll append the element from the ContactView
into the list element accepted from the constructor:
class ContactListView {
constructor(element, data) {
this.element = element;
this.data = data;
this.render();
}
render() {
this.data.forEach((item) => {
const itemView = new ContactView(item);
this.element.appendChild(itemView.element);
});
}
}
Notice that the ContactView
element had to be appended and placed into the DOM.
This is because it is only responsible for managing the element it created, something else will have to insert it.
Creating View Instances
Similar to the detail view, niether of these classes will do ANY work until we actually create instances of them.
Here, we only have to create a single ContactListView
and the render
function and loop will take over from there.
const contactData = [
{
first: `Frank`,
last: `Underwood`
},
{
first: `Zoe`,
last: `Barnes`
},
{
first: `Peter`,
last: `Russo`
}
];
const contactEl = document.querySelector(`.contacts`);
new ContactListView(contactEl, contactData);
Once again, here's an interactive example that will run the code above:
Contacts