3
\$\begingroup\$

This particular snippet is a simple to-do app that allows the user to add new items to the list, mark them as done, delete a single item, or delete all items.

What I would be looking for advice on are my use of a function constructor. It may be overkill for something like this, but it is more of a learning exercise to become familar with the process. Could the building up of each list item be done in a better way?

On the use of an IIFE, my understanding of these is that it can help self-contain code snippets and ensure they keep their scope. Would this be a good practice going forward, or do they have their best use cases?

If there are other areas of improvement I would welcome input regarding those. Thanks.

(function(){
 "use strict"
 let form, listArea, formInput, clearList;
 // Function constructor
 // Will build up each list item
 // With associated functions
 const Task = function (taskName) {
 this.taskName = taskName;
 this.buildTask = function () {
 let newListItem = document.createElement('li');
 newListItem.innerHTML = `<span></span>${this.taskName}<button class="remove-item">Bin It</button>`;
 newListItem.querySelector('.remove-item').addEventListener('click', removeItem);
 newListItem.querySelector('span').addEventListener('click', markDone);
 listArea.appendChild(newListItem);
 }
 }
 function markDone(e) {
 e.currentTarget.parentNode.classList.toggle('done');
 }
 function removeItem(e) {
 e.currentTarget.parentNode.remove();
 }
 function clearAllItems() {
 let listAreaItem = listArea.querySelectorAll('li');
 listAreaItem.forEach((item) => {
 item.remove();
 })
 }
 // On form submit
 // Create new instance of Task
 function formValidate(e) {
 e.preventDefault();
 const value = formInput.value
 if(!value) {
 formInput.dataset.state = 'invalid';
 return;
 }
 // Trim whitespace from the input
 const trimValue = formInput.value.trim();
 if(trimValue) {
 formInput.dataset.state = 'valid';
 new Task(trimValue).buildTask();
 formInput.value = '';
 }
 }
 function startup() {
 form = document.getElementById('form');
 listArea = document.getElementById('listArea');
 formInput = document.getElementById('addToField');
 clearList = document.getElementById('clearList');
 // Check for an submit on the form field
 form.addEventListener('submit', formValidate);
 clearList.addEventListener('click', clearAllItems);
 }
 window.addEventListener('DOMContentLoaded', startup);
})();
* {
 box-sizing: border-box;
}
body,
button,
form input,
form button {
 font-family: 'Space Mono', monospace;
}
button {
 color: #fff;
 border: none;
 background: #7e7e7e;
 height: 60px;
 padding: 0 25px;
}
button:hover,
ul li span:hover {
 cursor: pointer;
}
.input-area {
 max-width: 600px;
 margin-left: auto;
 margin-right: auto;
 padding: 50px;
}
#form {
 display: flex;
}
form input {
 border: none;
 border-bottom: 2px solid rgba(0,0,0,0.25);
 height: 60px;
 flex-grow: 1;
 font-size: 20px;
}
form input[data-state="invalid"] {
 border-color: red;
}
form input[data-state="valid"] {
 border-color: green;
}
form button {
 height: 60px;
 border: 2px solid rgba(0,0,0,0.25);
 flex-basis: 175px;
 flex-grow: 0;
 flex-shrink: 0;
 border: none;
 color: #fff;
}
ul {
 list-style: none;
 padding-left: 0;
}
ul li {
 display: flex;
 line-height: 60px;
 background-color: #e3e3e3;
 margin: 5px 0;
}
ul li.done {
 background-color: limegreen;
}
ul li span {
 display: inline-block;
 width: 60px;
 height: 60px;
 background-color: rgba(0,255,0,0.2);
 margin-right: 20px;
}
ul li.done span {
 background-color: green;
}
ul li button {
 height: 60px;
 padding: 0 20px;
 margin-left: auto;
 background-color: #db4646;
}
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>To Do App</title>
 <link rel="stylesheet" href="style.css">
 <link href="https://fonts.googleapis.com/css2?family=Space+Mono&display=swap" rel="stylesheet">
</head>
<body>
 <main>
 <div class="input-area">
 <h1>Do it.</h1>
 <form id="form">
 <input id="addToField" type="text">
 <button id="submitToList" type="submit">Add to List</button>
 </form>
 <ul id="listArea"></ul>
 <button id="clearList">Clear List</button>
 </div>
 </main>
</body>
<script src="script-2.js"></script>
</html>

asked Jun 16, 2020 at 22:17
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

On the use of an IIFE, my understanding of these is that it can help self-contain code snippets and ensure they keep their scope. Would this be a good practice going forward, or do they have their best use cases?

Usually you'd write ES5 modules and use a build tool like Rollup, Webpack or Parcel to compile your code into something understandable by older browsers.
Learning and keeping up with the whole ecosystem of NodeJS-based development tools can be overwhelming though.

If there are other areas of improvement I would welcome input regarding those.

Modern frameworks like React tend to approach working with DOM differently: instead of changing the existing tree of nodes, they throw away and recreate the whole UI on every change.

You'd need four things:

  1. A variable that holds the current state. I believe in your case that would be a list of tasks, e.g. {taskName: "task name", done: true}.
  2. Event handlers that respond to DOM events.
  3. A function that takes the current state and returns a new tree of DOM nodes, with event handlers attached.
  4. (Optional) A convenience function for wrapping event handlers. Each event handler changes state based on the current state and the event, and then replaces the old DOM with the new DOM created by function (3). This way defining an event handler is as simple as writing (state, event) => doSomethingAndReturnNewState(...).

This way you can store your whole application state in JS. Having a single source of truth makes it easier to keep track of all the possible states your application can be in.

answered Jun 18, 2020 at 13:26
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.