Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

addEventListener
A call on an element that registers a listener for one kind of event.
closest
A way to find the nearest parent of an element that matches a rule you give, starting with the element itself.
closure
A function together with the variables from the place it was written, which stay available when it runs later.
default behaviour
What the browser does on its own when an event happens, such as following a link or submitting a form, before any script intervenes.
DOM
The tree of objects a browser builds from the page, which a script can read and change while the page is open.
element
One item in the page tree, such as a heading or a button, which a script can find and change.
event
Something that happens on the page, such as a click, a key press, or a form being submitted, which a script can respond to.
event bubbling
The way an event rises from the element that received it up through each of its parents.
event target
The element that actually received the action, which may be a child of the element whose listener is running.
function
A reusable block of code that can be called with values and can return an answer to whoever called it.
handler
The function you give to a listener, which the browser runs when the event it waits for happens.
listener
A function registered on an element to wait for one kind of event and run each time that event reaches it.
property
A named value stored on an object, usually read and written with a dot, such as the text of an element.
reference
A value that points at an object rather than holding a copy, so a change made through one is visible through the other.
scope
The part of a program where a name can be used, decided by where it was declared.
variable
A name that holds a value so you can use it again; a constant cannot be pointed at a different value later.

JavaScript from the ground up

A small app, end to end

Everything at once: a to-do list that reads a field, listens for a submit, builds list items and keeps the page in step.

Part 11 of 12

Advanced18 min readBack to Courses

Everything, in one small app

A to-do list is the smallest thing that uses the whole language: a value from a field, a decision about empty input, a new element built and appended, and an event that starts it all. No framework, no build step — the ideas from this course, in order.

It is also worth building once by hand. Every framework you meet afterwards is a tidier way of writing these same five steps, and recognising them is what makes the tidier version make sense.

The order matters as much as the pieces. Cancel first, read second, decide third, build fourth, place fifth, clear last. A step out of order produces a specific symptom: clearing before reading empties the field, and appending before deciding adds the blank row you meant to reject.

The checklist for this app

  • The form listens for submit, and the page is stopped from reloading.
  • The field’s value is read and trimmed.
  • Empty input is ignored, with nothing built and nothing added.
  • A list item is created and its text set from the value.
  • The item is appended to the list.
  • The field is cleared, ready for the next entry.

Keep the list, draw the list

The important decision in a small app is where the truth lives. Keep the to-dos in an array and treat the page as a drawing of that array. Adding an entry changes the array, then a render function clears the list and builds every item again from the current data.

That sounds slower than appending one new item, and it is a little. What it buys is agreement: the page cannot show an item the array does not have, or miss one it does. A count and an empty-state message are then derived from the same array, so they cannot disagree either.

A worked submit, end to end

Suppose the visitor types buy bread and presses Add. The submit event fires, the handler calls preventDefault, and the page stays put. The handler reads input.value, trims it to buy bread, and finds it non-empty. It creates an li, sets its text, appends it to the list, and clears the field. The list now has one more row and the field is ready for the next entry.

Type spaces only and press Add: the trimmed value is empty, so the guard returns before anything is built. That early return is what keeps blank rows out of the list. Without it, the same steps would append an empty item, and the visitor would have to delete it by hand.

Reading the finished app

When the app misbehaves, read it in the order it runs. Was the form found? Did the listener attach? Did the handler fire? What did the field contain after trimming? Was an item created and appended? Each question is a console.log away, and the first one that gives an unexpected answer is the bug.

That habit scales to larger programs. The page is a sequence of small transformations, and a bug is a place where one transformation received something other than what the previous one produced. Logging the value at the seam is faster than reading the whole file again.

Three ways a small app drifts: list.innerHTML += ... reparses every existing item and throws away its listeners; appending to the page but not to the array leaves the two out of step on the next render; and appending the same element reference twice moves it instead of copying it, so an item vanishes from where you expected it.

The to-do list, finished

Wire the form: stop the page reloading, read the field, ignore an empty entry, build a list item and append it, then clear the field.

Live Preview
Console output will appear here...

4 left to do

  • The form listens for submit
  • The page is stopped from reloading
  • A list item is created
  • It is appended to the list

Listen for submit on the form; event.preventDefault(); read input.value.trim(); document.createElement("li"); list.append(item); input.value = "".

The same list, drawn from state

Keep the entries in an array, render the whole list from it with a loop, show how many there are, and let the clear button empty both the array and the page.

Live Preview
Console output will appear here...

3 left to do

  • The entries live in an array
  • The list is drawn with a loop
  • The list can be emptied

Start const todos = [];; a render function does list.replaceChildren(), then a forEach that builds the items; the clear button sets todos.length = 0 and renders again.

Try these next

  • Add a delete button to every item and remove that entry from the array before rendering again.
  • Show "Nothing yet" in the list when the array is empty.
  • Reject an entry that is only spaces, and say why in the message line.

Where to go next

You have the language now: values, decisions, loops, functions, arrays and objects, the DOM, events, forms, templates, dialogs and your own elements. What is left is mostly library knowledge — the same ideas applied to problems that come with names.

Three directions worth knowing about. Modules split a large program into files that import from each other. fetch asks a server for data and hands it back as JSON — the same loads idea from Python, over the network. And a framework is a tool for building interfaces that change often; every one of them is built on the DOM, events and state you have just used by hand.

The way forward is a small app you actually want — a habit tracker, a recipe box, a reading list. Keep the checklist beside it, and read other people’s code when it confuses you.

The best next program is one you want to exist. Want is what makes you finish it, and finishing is what teaches.

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

Which order is right for handling a form submission?