Studio 7
Prototyping exercise
You have 15 minutes to prototype a chat app, then 15 minutes to test it in two rounds (more detailed instructions will be given at studio).
Go deep, rather than broad. Pick one feature or one interaction that differenciates your app from others, and create a paper prototype for that. Decide on a specific task for your user testing that you will ask your user to perform. Try to cover as many aspects of the interaction that the user is likely to encounter during that task as possible. Don't just think of the happy path, but also of edge cases. Also, don't just think of whole screens, but also of individual components (e.g. if you have a dropdown menu, create its popup menu as well, so you can add it under it if your user clicks on it). Remember that prototypes are sloppy, don’t worry about making it look pretty and don't spend too much time on individual details.
To-Do list without Vue
We will practice DOM & Events by completing the implementation of the same to-do list we worked on in studios 1 and 3, but this time with vanilla JS (= JS without a framework).
While it's generally a better software engineering paradigm to separate data from UI, to keep things simple in this app (and to get more DOM practice), we will treat the DOM as the source of truth for our data, which is how most beginning JS programmers start out.
Start by forking studio7-starter and cloning your fork to your computer.
Take some time looking over the existing code. Ask questions for anything you don’t understand. By the time we move to the steps below, we expect you to generally understand the skeleton code, even if there are parts that are a bit fuzzy (e.g. it's ok to not fully understand how imports and exports work as we haven't modules yet).
It may help to view the code on GitHub (index.js
, index.html
) ,
as it displays a clickable list of internally defined functions in the sidebar.
Here is a cheatsheet for some things used in the code:
??
operator for providing default values / alternatives when a value is empty (null
orundefined
)?.
operatorfoo?.bar
is likefoo.bar
, but more forgiving iffoo
doesn’t existlocalStorage
for storing data locally in the browserJSON.parse(string)
andJSON.stringify(object)
to parse and serialize JSONelement.insertAdjacentHTML(position, html)
to insert HTML into the DOM- JS Modules
- Selector-based DOM traversal
container.querySelector(selector)
to get a reference to an element by CSS selectorcontainer.querySelectorAll(selector)
to get a reference to all matching elements by CSS selectorelement.closest(selector)
to get the closest ancestor matching a selector (or self if it matches)element.matches(selector)
to check if an element matches a selector
- Low level DOM traversal
element.previousElementSibling
to get the previous sibling element (i.e. not a text node)element.nextElementSibling
to get the next sibling element (i.e. not a text node)element.firstElementChild
to get the first child element (i.e. not a text node)element.lastElementChild
to get the last child element (i.e. not a text node)
- Simulating user actions
element.click()
to simulate a click on an elementelement.focus()
to focus on an element
Step 1: Update the count of done items when an item is checked
You can implement it using either event delegation, or by adding an event listener to each button individually in the addItem()
function that creates tasks.
To monitor changes to the done checkbox, you can use any of these events:
All of these events bubble, so all can be used with event delegation.
Step 2: Implement the delete button
The delete button should remove the task from the list, update both counts, and focus the previous element (if one exists) or the next one otherwise (if one exists).
You can implement it using either event delegation,
or by adding an event listener to each button individually in the addItem()
function that creates tasks.
Useful resources:
Step 3: Arrow keys to move between tasks
While the Enter and Backspace shortcuts can be implemented with either keyup
or keydown
events,
the arrow keys should be implemented with keydown
to allow for continuous movement (i.e. holding down the up arrow key quickly moves across multiple items).
Useful resources:
keydown
eventkeyboardEvent.key
to get the keyboard key that was pressed as a readable name (e.g."Enter"
)
Step 4: Implement the "Clear completed" functionality
This involves two components:
- Make the "Clear completed" button actually trigger the
clearCompleted()
function - Implement the
clearCompleted()
function.- One way to do this would be to loop through all the tasks and remove the ones that are done by simulating a click on their delete button
- You can even use
:has()
and the descendant combinator to get the buttons of the tasks that are done in one line of code!
Do not duplicate the deletion code from Step 1, per the DRY principle. Either turn it into a function that is called in both places, or simulate a click on the delete button.