-
-
Notifications
You must be signed in to change notification settings - Fork 155
Updated ToDo List exercise to promote modularization using ES Modules #745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# What is JavaScript Modules? | ||
JavaScript modules let us organize code into separate files, making the code easier to manage and reuse. We can export parts of one file (like functions or variables) and import them into another to keep our code clean and modular. | ||
|
||
## Different Module Systems | ||
|
||
JavaScript has two main ways to handle modules: | ||
|
||
- **CommonJS** is the older format used mostly in Node.js. It uses `require` and `module.exports`. | ||
|
||
- **ES Modules** (ESM) are the modern, standard way for browsers and Node.js. They use `import` and `export`. | ||
|
||
They are **not** fully compatible. | ||
|
||
## Where can I learn ESM? | ||
- [Modules, introduction](https://javascript.info/modules-intro) | ||
- [JavaScript modules -- JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Using ESM with Node.js, Jest, and `jsdom` | ||
|
||
## Node.js | ||
|
||
Node.js supports both CommonJS and ESM, with CommonJS being the default module system. | ||
|
||
To use ESM, we can add `"type": "module"` to `package.json`, or we can name the JS script files with `.mjs` file extension. | ||
|
||
**Important**: | ||
- Avoid mixing CommonJS and ESM in the same project unless you know what you're doing. | ||
|
||
|
||
## Jest | ||
|
||
[Jest’s support for ESM](https://jestjs.io/docs/ecmascript-modules) is still experimental, and may require additional configuration to work correctly. | ||
|
||
One way to execute Jest test script that uses ESM is to | ||
|
||
1. **Update the custom `test` script in `package.json`**: | ||
```javascript | ||
"scripts": { | ||
"test": "NODE_OPTIONS=--experimental-vm-modules jest" | ||
} | ||
``` | ||
|
||
**Note**: On Windows, use **`set`** instead | ||
```javascript | ||
"scripts": { | ||
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest" | ||
} | ||
``` | ||
|
||
|
||
2. **Run a specific Jest test script using**: | ||
|
||
``` | ||
npm test -- <test_script_filename> | ||
``` | ||
|
||
**Note**: The `--` is optional if you do not have arguments to be forwarded to the underlying jest command. | ||
|
||
|
||
## `jsdom` | ||
|
||
[**`jsdom`**](https://github.com/jsdom/jsdom), a pure-JavaScript implementation of DOM for use with Node.js, **does not yet support** `<script type="module">` tags in HTML. | ||
|
||
Testing an ESM-based application with `jsdom` requires additional configuration and third-party tooling. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Why modularize code? | ||
|
||
Modularizing code means breaking a program into smaller, self-contained pieces (modules), each responsible for a specific functionality. This approach offers several key advantages: | ||
|
||
- Reusability – You can use the same code in different parts of a project or in other projects. | ||
- Maintainability – It's easier to fix bugs or update features when code is organized into smaller parts. | ||
- Separation of Concerns – Each part of the code handles a specific task, keeping things clear and organized. | ||
- Team Collaboration – Multiple people can work on different modules at the same time without conflict. | ||
- Scalability – You can add new features more easily as the project grows. | ||
- Testing – Smaller modules are easier to test individually. | ||
- Readability – Modular code is easier to read, understand, and navigate. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's probably worth mentioning explicitly that when you There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My intention is to introduce the bare minimum of ESM through an example to get them started, and expect them to find out more about ESM from external resources:
Too much info initially could overwhelm many of them. |
||
## How to break a program into smaller modules? | ||
|
||
This is a relatively big topic and you will learn more about how to modularize a web app in the SDC course. | ||
|
||
For starters, we recommend focusing on breaking a web app into the **non-UI part** and the **UI part**. | ||
|
||
### The Non-UI Part of a Web App | ||
|
||
This is the part of the app that works behind the scenes, without any user interface (UI). | ||
|
||
It focuses on: | ||
- ✅ How to represent data in the app | ||
- ✅ What operations are needed to support data access and manipulation | ||
|
||
### The UI Part of a Web App | ||
|
||
This is the part of the app that interacts with the user interface (UI). | ||
|
||
It focuses on: | ||
- ✅ How to collect user input | ||
- ✅ How to present data on the screen | ||
- ✅ Calling functions in the non-UI part to process the data | ||
|
||
### Example: The ToDo App | ||
- The non-UI part is implemented in `todos.mjs` | ||
- The UI part is implemented in `script.mjs` | ||
|
||
Note: For a larger codebase, each part could be divided into multiple modules or files. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,48 @@ | ||
# Todo-list | ||
# ToDo List App | ||
|
||
## Explanation | ||
The files in this folder implements a ToDo List App that allows a user to | ||
- Create a new ToDo task | ||
- Delete a ToDo task | ||
- Display all ToDo tasks | ||
- Changing the "completed" status of a ToDo task | ||
|
||
This is a super handy, super simple to do list. | ||
|
||
You will be given a list of tasks which are "To Do". We call these tasks "ToDos" | ||
|
||
Each item in the list should have 2 buttons: | ||
|
||
- One to click when the ToDo has been completed - it will apply a line-through style to the text of the ToDo. | ||
- A second to delete the ToDo. This could be used to delete completed ToDos from the list, or remove ToDos that we are no longer interested in doing. | ||
|
||
We also want to be able to add ToDos to the list using an input field and a button. When ToDos are created this way they should be added to the list with the 2 above buttons. | ||
|
||
More details for the implementation of this challenge can be found in `script.js` | ||
Each ToDo task has two properties: | ||
- `task`: A string describing the task | ||
- `completed`: a Boolean value that indicates whether the task is completed or not | ||
|
||
## Installation | ||
|
||
To view the website, open index.html in a browser. | ||
|
||
## Example Solution | ||
To view the website, open `index.html` with Live Server in VS Code. | ||
|
||
A basic example of this can website can be found here | ||
**Note**: The app is loaded **as ES modules** in the HTML file, and as such, the HTML file must be accessed via the HTTP or HTTPS protocol. | ||
|
||
https://chrisowen101.github.io/ToDoListSolution/ | ||
## Understanding how the code is organized as ES modules | ||
|
||
This covers only the basic tasks, not the advanced tasks. | ||
- [What is ES Modules?](00-what_is_ES_modules.md) | ||
- [How to use ES modules with Node.js and Jest?](01-using_esm_with_nodejs_and_jest.md) | ||
- [A guide to modularize a web app](02-guide_to_modularize_code.md) | ||
|
||
## Instructions | ||
|
||
The `populateTodoList()` function should iterate over the list of todos that we are given at the start, it should create a `<li>` for the todo along with some other stuff that you can find in index.html and below. | ||
|
||
The items in the todo list are currently hard-coded into the HTML, refactor the code so that this function creates them and adds the following functionality to them: | ||
In this exercise, your objective is to implement additional features. | ||
|
||
Each todo should have this HTML inside it: | ||
#### Feature 1: Mass delete of completed ToDos | ||
|
||
```html | ||
<span class="badge bg-primary rounded-pill"> | ||
<i class="fa fa-check" aria-hidden="true"></i> | ||
<i class="fa fa-trash" aria-hidden="true"></i> | ||
</span> | ||
``` | ||
Add a "Delete completed tasks" button that, when clicked, will delete all the completed ToDos. You should | ||
- In `todos.mjs`, implement a function to delete all completed tasks in the given ToDo List | ||
- In `todos.test.mjs`, implement a test to check your function. | ||
- In `script.js`, call the function to delete all completed tasks whenever the user clicks a "Delete All" button. | ||
|
||
The first `<i>` tag needs an event listener that applies a line-through text-decoration styling to the text of the todo. It should remove the styling if it is clicked again. | ||
#### Stretch 1: Set deadlines for ToDos | ||
|
||
The second `<i>` tag needs an event listener that deletes the parent `<li>` element from the `<ul>`. | ||
|
||
## Advanced Challenge | ||
|
||
### Mass delete of completed ToDos | ||
|
||
Develop the ToDo list further and allow users to delete all completed ToDos. | ||
|
||
Add a button that users can click that will iterate through the list of ToDos and then delete them only if they have been completed. | ||
|
||
## Extra Advanced Challenge | ||
We want users to be able to set, and see, deadlines for their ToDos. | ||
|
||
### Set deadlines for ToDos | ||
When creating a ToDo we want the user to be able to use a datepicker input to specify a deadline for the Todo. | ||
If no date is selected, the ToDo is considered having no deadline. | ||
|
||
We want users to be able to set, and see, deadlines for their ToDos. | ||
When displaying a ToDo in the list, display the deadline only if the ToDo has one. | ||
|
||
When creating ToDos we want the user to be able to use a datepicker input so they can see when they need to complete the ToDo. The date can be added to the ToDo in the list. If there is no date set when the ToDo is created then this can be skipped. | ||
#### Stretch 2: EXTRA CHALLENGE | ||
|
||
EXTRA CHALLENGE: instead of displaying the date on the ToDo, implement a countdown of days left until the deadline. You can use the Javascript Date reference to accomplish this: | ||
Instead of displaying the date on the ToDo, implement a countdown of days left until the deadline. You can use the Javascript Date reference to accomplish this: | ||
https://www.w3schools.com/jsref/jsref_obj_date.asp |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,40 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Title here</title> | ||
<link rel="stylesheet" href="style.css" /> | ||
</head> | ||
<body> | ||
<form> | ||
<div> | ||
<input type="text" placeholder="New todo..." /> | ||
</div> | ||
<div> | ||
<button type="submit">Add Todo</button> | ||
<button | ||
type="button" | ||
id="remove-all-completed" | ||
class="btn btn-primary mb-3" | ||
> | ||
Remove all completed | ||
</button> | ||
</div> | ||
</form> | ||
<script src="script.js"></script> | ||
</body> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> | ||
<title>ToDo List</title> | ||
<link rel="stylesheet" href="style.css" /> | ||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"> | ||
|
||
<script type="module" src="script.mjs"></script> | ||
</head> | ||
<body> | ||
<div class="todo-container"> | ||
<h1>My ToDo List</h1> | ||
|
||
<div class="todo-input"> | ||
<input type="text" id="new-task-input" placeholder="Enter a new task..." /> | ||
<button id="add-task-btn">Add</button> | ||
</div> | ||
|
||
<ul id="todo-list" class="todo-list"> | ||
</ul> | ||
|
||
<!-- | ||
This is a template for the To-do list item. | ||
It can simplify the creation of list item node in JS script. | ||
--> | ||
<template id="todo-item-template"> | ||
<li class="todo-item"> <!-- include class "completed" if the task completed state is true --> | ||
<span class="description">Task description</span> | ||
<div class="actions"> | ||
<button class="complete-btn"><i class="fa-solid fa-check" aria-hidden="true"></i></button> | ||
<button class="delete-btn"><i class="fa-solid fa-trash" aria-hidden="true"></i></button> | ||
</div> | ||
</li> | ||
</template> | ||
|
||
</div> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "todo-list", | ||
"version": "1.0.0", | ||
"license": "CC-BY-SA-4.0", | ||
"description": "You must update this package", | ||
"type": "module", | ||
"scripts": { | ||
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/CodeYourFuture/CYF-Coursework-Template.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/CodeYourFuture/CYF-Coursework-Template/issues" | ||
}, | ||
"homepage": "https://github.com/CodeYourFuture/CYF-Coursework-Template#readme", | ||
"devDependencies": { | ||
"jest": "^30.0.4" | ||
} | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels maybe worth giving an "all together" vs "split out" example alongside this content? I think "separation of concerns" and "testability" are quite hard things to visualise without an example if you haven't experienced them before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think some examples to illustrate those ideas could be useful. I can prepare them.