Sortable and filterable list
Implement list sorting and filtering using custom elements and an event bus
The way of kata
Kata is an exercise for muscle memory. It's not intended to fill your brain with information but train your fingers to react. The information is there to give you the why, but your fingers need to learn the how.
The material on this page is presented in a specific order — from least specific to highly technical. You will learn the most by jumping in as soon as you have some idea of what you should do. Once you're done, read the rest of the material and check your solution.
All katas are designed to be doable without using 3rd party libraries (and, in fact, the point is to also learn how to do what these libraries do).
To make the best of katas, observe the following rules.
- Don't rush.
- When stuck, take a break and do something unrelated.
- Do not copy/paste code. Always retype everything.
- Do not use AI tools to generate code.
- Try to do something that wasn't in the instructions, experiment.
- Repeat the kata from time to time, even if you think you've got it.
- You have mastered the kata once you are able to complete it without thinking too much.
Remember, the goal is not to get it done, but to get some practice.
Introduction
In this exercise you will practice sorting and filtering lists as well as tying different parts of the UI using custom elements and an event bus.
Skills you will acquire
- Using custom elements
- Using an event bus
- Manipulating lists of DOM nodes
- Advanced animation techniques (optional)
Objective
- Using the provided HTML file, implement the two custom elements to facilitate list sorting and filtering
Check your solution
- When page loads, the search and sort form controls appear above the list
- When you type a keyword in the text field, the list only shows cities such that the keyword appears anywhere in the city name
- The keyword match is case-insensitive
- When you change the value of the select list, the ordering of the list changes
- Sorting and filtering both apply to the list at the same time
- (Optional) Animate the changes in the list
Materials
Keep in mind
The provided HTML already includes two custom elements,
<x-filter-controls> and <x-filtered-list>. Each element has a specific
job: the <x-filter-controls> deals with the user input, while the
<x-filter-list> deals with the list.
Communication between the two custom elements can be established using an event
bus. In the browser, every element as well as the global window objects are
already event busses. They all implement the EventTarget interface.
Additionally the EventTarget constructor can be used directly to create a
custom bus. Try both options.
For the event name, I recommend using a name with an x- prefix, just like the
custom elements. This is a reliable way of avoiding potential conflicts with
event names you may not be aware of. As a good naming practice, consider the
naming pattern of the platform (identify the theme of the event names in the DOM
API, in other words), and try to construct a name that follows the theme.
There are three ways to communicate information in this situation.
- Keep the information in a variable that is visible to both custom elements and use the event as just a signal that the information is changed.
- Expose the information on the
<x-filter-controls>element (e.g., by defining getters), and trigger the event on the element so that it bubbles up to thewindowobject where the<x-filtered-list>will listen for it. In this case, theevent.targetrepresents the<x-filter-controls>element. - Do not keep the information at all, and send it using a
CustomEventin itsdetailsproperty.
You should practice all three options, and note each one's advantages and disadvantages.
The filtering can be applied in two ways.
- You can toggle the individual items on and off by using their
hiddenattribute. - You can keep the list of all items in an array and pre-filter that array, and then insert those items into the DOM tree while removing items not found in the array.
The difference in complexity between the two solutions is about as what it sounds like. You should still try both approaches as practice.
Sorting is done in a similar way as the second method of filtering. You first sort an array containing the list items, and then you append the items one by one. Remember that a DOM node cannot exist in two places at the same time. By appending the items in order, they are simultaneously removed from whatever position it was in previously.
To animate the changes, use the FLIP technique.
Reading list
EventTarget(MDN)- Creating and triggering events (MDN)
hidden(MDN)Element.append()(MDN)- Animating Layouts with the FLIP Technique (CSS-Tricks)
Hints & spoilers
Hint: caching element text
The following technique may come in handy for this exercise. DOM nodes are objects, just like any object in JavaScript. This means that you can assign custom properties on it, in addition to assigning the built-in ones. The custom properties will not affect the DOM element in any way, but they can serve to bundle additional data. Here's an example:
var $city = $listItem.querySelector('.city')
$listItem._city = $city.textContent
Once assigned, the _city property can be access on this particular $listItem
element whenever it is retrieved from the DOM tree.