Webbo3 Level 2 · JavaScript Development · Day 5 of 20
Project 1: Make It Work
Your first solo build. A problem statement, not a tutorial, and a Friday where you defend what you wrote.
By the end of today you can
- Turn a problem statement into a working application without being given steps
- Keep your data in one array and draw the page from it
- Find the right item by its id, and avoid the string-versus-number trap
- Push your work to GitHub with a README somebody else could follow
- Demonstrate it live and explain any line you are asked about
There is no tutorial today. You are given a problem and a standard, and the gap between them is the work.
This is deliberate. Copying a tutorial teaches you to copy tutorials. The first time you face a blank file with nobody to copy is the first time you find out whether you can actually do this. Better that it happens here, on a Friday, with your instructor in the room.
Before the brief, two ideas the whole project stands on. Understand these and the ten requirements become ten small jobs instead of one big fog.
1. One Array of Truth, One render()
Definition
Rendering from data means your tasks live in one JavaScript array, and one function, render(), draws the page from that array. Every action (add, complete, delete) changes the array and then calls render() again. You never read the page to find out what tasks exist.
Real-Life Example
A restaurant keeps its orders in the order book, and the kitchen screen shows what the book says. When an order changes, the waiter changes the book, and the screen redraws from it. Nobody walks over to the screen and squints at it to work out what the orders are.
The array is the order book. The page is the screen. You saw this on Day 4 in the final scenario; today the whole project is built this way.
How It Works
- State: the array of tasks, plus the current filter and search text.
- Derived data: a function such as
visibleTasks()that works out which tasks should be on screen right now. It never touches the page. - Render:
render()draws exactly whatvisibleTasks()returns. - Actions: every click or keystroke changes the state, then calls render.
Example 1: Deciding What Is Visible
toLowerCase() turns text into small letters, so a search for "GitHub" still matches "github". includes() asks whether one piece of text appears inside another.
visibleTasks() answers one question: given the filter and search right now, which tasks should be visible? Separating "what is true" from "what is drawn" is the most useful structural idea in this project, and it is exactly what React will do for you in Level 3.
Example 2: The Render Loop on a Page
task.done ? 'done' : '' is the ternary: a one-line if/else that gives back a value. You will see it in the next example. Read it as "if task.done, then 'done', otherwise nothing". Use it only for short choices like this; anything longer belongs in an if.
Reading the list back off the page ("how many li elements are there?") to decide what the tasks are works until the filter hides some of them. Then the page no longer shows every task, and your count, your search and your delete all go wrong at once. The array always knows; the page only shows.
Picture the order book and the kitchen screen. Every change goes into the book first, and the screen is simply redrawn from the book. If the screen and the book ever disagree, the book is right.
2. Every Task Needs an id
Definition
An id is a number (or text) that belongs to one task and never changes. You stamp it onto the task's element with a data-id attribute, and when that element is clicked you read it back with dataset.id to find the right task in the array.
Real-Life Example
A cloakroom ticket. The attendant does not remember that your coat is "the third one from the left", because coats come and go and the positions change. Your ticket number stays the same, so it always finds your coat.
The position (index) of a task changes the moment anything before it is deleted. Use the index and you will eventually delete the wrong task. The id never moves.
Common Mistake: dataset Always Gives You Text
Everything read from dataset is a string. Your ids in the array are numbers, and === checks the type too (Day 1). So without a conversion, the task is never found.
That is Day 1 coming back: "2" and 2 are different types. It will cost somebody in your cohort an hour today. Always wrap it: Number(element.dataset.id).
Picture the cloakroom: the ticket number goes on the coat hanger (data-id), and you hand the same number back to collect it. Just remember the ticket is printed as text, so read it as a number before you compare.
3. The Brief
Build a personal task and productivity application that lets a person create, complete, edit, delete, filter and search their tasks. It runs entirely in the browser. No backend, no framework, no library.
That is the entire brief, and it is meant to feel slightly too open. Decide the rest yourself: what a task looks like, what happens to a completed one, what the empty state says. Those decisions are part of what is assessed.
What It Must Do
| # | Requirement | Proves you understood |
|---|---|---|
| 1 | Add a task from a text field | Events, form handling, preventDefault |
| 2 | Refuse an empty task with a visible message | Validation, falsy values |
| 3 | Mark a task complete, and uncomplete again | Changing state, re-rendering |
| 4 | Edit the text of an existing task | Finding one item by id, updating it |
| 5 | Delete a task | Event delegation, closest, ids |
| 6 | Filter: all, active, completed | filter, re-rendering from data |
| 7 | Search tasks as the user types | The input event, filter |
| 8 | A count of what is left | Derived values |
| 9 | An empty state when there is nothing to show | Thinking about the user |
| 10 | Works on a phone-width screen | Last month's CSS, still your job |
One array of task objects, one render() function that draws it, and every action changes the array and calls render() again. That is section 1 of today, and it is worth 20 marks on its own.
4. What to Hand In
- A public GitHub repository with real commit messages. Not one commit called "final": at least six, each describing what changed.
- A README with: what it does, a screenshot, how to run it, and one honest paragraph on what you would improve with more time.
- The folder structured the way you learned last month:
index.htmlat the root,css/andjs/. - A deployed link if you can manage it. GitHub Pages is free and takes ten minutes. Not required today, required from Day 18.
5. The Friday Evaluation
You do not submit and go home. You demonstrate, and you answer questions. Fifteen minutes each.
| Part | What happens | Marks |
|---|---|---|
| Demo | You drive. Show every one of the ten requirements working. | 30 |
| Code walkthrough | Open your JavaScript and explain how the render loop works. | 20 |
| The bug story | Describe one bug you hit, how you found it, and how you fixed it. | 15 |
| Three questions | Technical questions on your own code, picked live. | 20 |
| Repo and README | Commit history, structure, and a README that helps. | 15 |
Never submit code you cannot explain. If you cannot say what a line does and why it is there, it does not belong in your project yet. This applies equally to code you found online and code an AI wrote for you.
The Kind of Question You Will Be Asked
- Show me where the task actually gets deleted. Why does that work for a row you added thirty seconds ago?
- You used === everywhere. What would break if you swapped them for ==?
- Your search runs on every keystroke. What happens with two thousand tasks?
- If I typed
<b>hello</b>as a task, what appears on screen, and why? - Walk me through what happens, in order, between my click and the row disappearing.
The evening before, open your own file and read it top to bottom out loud, saying what each block does. Anywhere you hesitate is a question you cannot answer yet, so go and understand that part. It takes twenty minutes, and it is the highest-return thing you can do the night before any technical interview for the rest of your career.
The Marking Rubric
| Band | What it looks like |
|---|---|
| Distinction, 85+ | All ten requirements work. Data lives in an array and the page is rendered from it. One delegated listener. User text handled with textContent. Readable names, small functions. A README somebody else could follow. Answers every question without hesitating. |
| Strong, 70 to 84 | All ten work. Structure mostly clean with some repetition. Explains the code confidently with one or two gaps. |
| Pass, 50 to 69 | Seven or more requirements work. Code runs but reads the page as its source of truth, or attaches a listener per button. Can explain most of it. |
| Not yet, below 50 | Requirements missing, or code the student cannot explain. Resubmit Monday. |
Questions You Will Have Today
I am stuck and it is 11am. Do I ask for help?
Yes, after fifteen minutes of your own attempt and not before. First write down three things: what you expected, what actually happened, and the two things you have already tried. Writing those three lines solves the problem outright surprisingly often, and when it does not, it turns "it is not working" into a question somebody can answer in thirty seconds.
Can I use code from a tutorial or from an AI?
Yes, on one condition, the same for both: you must be able to explain every line of it. You will be asked about specific lines this afternoon, picked at random.
I finished the ten requirements by 2pm. What now?
Do not add an eleventh. Delete every line that is not doing anything, rename anything vague (data, temp, x, handleClick2), and hand your laptop to the person next to you and watch them use it without helping. Every place they hesitate is a real finding.
Mine looks plain compared to the person beside me. Does that matter?
Not today. The rubric has no marks for visual design and twenty for whether the data and the render are separated properly. Make it work, then make it nice, in that order.
Tick Before You Move On
- ☐ All ten requirements work, and I checked each one deliberately
- ☐ My tasks live in an array and the page renders from it
- ☐ I convert every dataset id with Number() before comparing
- ☐ Delete uses one delegated listener and a real id, not an index
- ☐ I tested with bold as a task name and it showed as text
- ☐ Six or more meaningful commits and a README with a screenshot
- ☐ I read my own code aloud and can explain every line
Quick Recap
A problem statement, not steps: the decisions are part of the assessment. One array of truth, one render function, and every action changes the array then re-renders. Derived values, such as the count of what is left, are worked out, never stored. Ids live on elements as data-id and come back as text, so convert them with Number(). Never submit code you cannot explain, whoever or whatever wrote it.
Final Scenario
It is 4pm on Friday. Your instructor clicks Delete on a task you added a minute ago, then asks you to explain exactly what happened.
You can: the click bubbled to the one listener on the list, closest found the row, Number turned its data-id into a number, the array lost that task, and render drew the page again from the array. Five sentences, every one of them yours.
That is what "make it work" really means: not only that it works, but that you know why.
Next week, Day 6: modern JavaScript and modules. From here your code starts talking to the outside world: modules, asynchronous code, HTTP and real APIs, ending in your first group build.