Lesson 5 of 11
Creature Finder
A list you can search and filter. Three array methods do all of the work.
What you will learn
- .filter()
- .map()
- .includes()
- .toLowerCase()
- Redrawing from the data
- data- attributes
- The empty state
Before you start
Quote Typer. There you handled typing and read one item out of an array of objects. Here you work with the whole array at once.
What this page does
- Type in the box. The list shrinks as you type.
- Click Sea. It shrinks again, and the search still applies.
- Type something no creature matches. A message appears instead of a blank page.
- Clear the box and click All. Everything comes back.
Three methods, three jobs
Each one takes a function and runs it once for every item in the array. None of them changes the original array.
| Method | Its one job | What you get back |
|---|---|---|
.filter() | Keep some items, drop the rest | A new, shorter array |
.map() | Turn every item into something else | A new array, the same length |
.forEach() | Do a job with every item | Nothing |
The whole of the drawing is those three, one after another. Read it as one sentence: keep the ones that match, turn each of those into a card, then put every card on the page.
const found = creatures.filter(matches);
const cards = found.map(makeCard);
cards.forEach(function (card) {
list.appendChild(card);
});The test that filter runs
filter calls matches once for each creature. That function gets one creature and answers true or false. True keeps it.
function matches(creature) {
const rightHabitat = habitat === "all" || creature.habitat === habitat;
const rightName = creature.name.toLowerCase().includes(searchText);
return rightHabitat && rightName;
}.includes()asks whether one piece of text is inside another."Sea Otter".includes("ott")isfalse, because of the capital letters..toLowerCase()on both sides is what fixes that. The name is lowered here, and the search text was lowered when it was typed.&&means both halves must be true. That is what lets the search box and the buttons work together with no extra code.habitat === "all" ||is the escape hatch. When All is chosen, the first half is true and the habitat stops mattering.
A blank page looks broken
When nothing matches, an empty list is indistinguishable from a page that has crashed. So the code says why.
if (found.length === 0) {
const nothing = document.createElement("p");
nothing.className = "empty";
nothing.textContent = "No creatures match. Try a shorter search.";
list.appendChild(nothing);
}Build it step by step
Get all twelve on the page before you filter any of them. A filter you cannot see working is hard to debug.
Make the page
Make
index.htmlwith a search box, four buttons and one empty<div id="list">. Put the<script>tag at the end of<body>. Nothing shows yet.Write the data
In
finder.js, make thecreaturesarray. Each item is an object withname,habitat,artandfact. Four or five is enough to start.Draw all of them
Write
makeCard, then adrawfunction that loops the whole array and appends every card. No filtering yet. Reload. Every creature appears.Filter by name
Add the search box listener. Store what was typed in
searchText, then usecreatures.filter(...)indraw. Test it by typing part of one name.search.addEventListener("input", function () { searchText = search.value.toLowerCase().trim(); draw(); });Add the habitat buttons
Add the
data-habitatattributes and one listener for all four. Store the answer inhabitatand add that half tomatches. Now both work at once, and you wrote no code to combine them.Say when nothing matched
Add the empty state. Test it by typing letters no creature has.
Show the count
Write
found.lengthandcreatures.lengthinto the count line. This is the fastest way to see that the filter is doing what you think.
Try these changes
Make these changes in the files beside this guide. Each one only uses what this lesson has already covered. Tick each one when it works.
Check yourself
Three quick questions on this lesson. Get them all right to finish the lesson and earn a pack.
Loading your answers
Teacher's versionHow to run this lesson, what to check, and any answers. Students do not need this.
How to teach it
- Do
filterin the console before any of this is on a page.[1, 2, 3, 4].filter(function (n) { return n > 2; })and then ask what the original array is now. Unchanged. That surprises people and it is the whole idea. - Then
.map()on the same array. Ask what is different about the LENGTH of what came back. Filter can only get shorter. Map is always the same length. - Step 3 matters. Draw all twelve creatures with no filtering and stop. A student who cannot see the list yet cannot tell a broken filter from a broken card.
- Delete the
list.textContent = ""line on purpose and type three letters. The page fills with duplicates. Ask what happened before you say. This is the bug they will write themselves. - Make them try the search with
.toLowerCase()removed. Searching in lower case for a name that starts with a capital finds nothing, and the page looks like the filter is broken rather than the comparison.