<div id="todos">
<form method="post" action="/my-backend-script">
<input type="text" placeholder="What's next?" />
<input type="submit" value="Add" />
</form>
<ul></ul>
</div>
#todos {
font-family: sans-serif;
color: #444;
}
/**
* Todo List Input
*/
#todos form {
display: flex;
}
#todos form input[type="text"],
#todos form input[type="submit"] {
padding: 5px 10px;
border: 1px solid #666;
outline: none;
}
#todos form input[type="text"] {
flex: 1;
}
#todos form input[type="text"]:focus {
border-color: #369;
}
#todos form input[type="submit"] {
margin-left: 5px;
text-transform: uppercase;
}
/**
* Todos List
*/
#todos ul {
margin: 10px 0 0 0;
padding: 0;
border: 1px solid #ddd;
border-radius: 4px;
}
#todos ul li {
padding: 5px 10px;
border-bottom: 1px solid #ddd;
transition: background-color 500ms ease;
}
#todos ul li:last-child {
border-bottom: none;
}
#todos ul li:hover {
background-color: #cde;
}
/**
* App's State
*/
const todos = [
'buy milk',
'clean kitchen',
'learn js',
]
/**
* High level render loop handler
* instead of a huge complicated function,
* we use sub-functions to delegate part of
* the responsibilities and achieve a clear
* and readable code
*/
const render = () => {
resetDOMList()
todos.forEach(renderDOMListItem)
}
const resetDOMList = () =>
document
.querySelectorAll('#todos ul *')
.forEach($ => $.remove())
const renderDOMListItem = (item, index) => {
const li = document.createElement('li')
const txt = document.createTextNode(item)
li.appendChild(txt)
li.addEventListener('click', () => {
todos.splice(index, 1)
render()
})
document
.querySelector('#todos ul')
.appendChild(li)
}
/**
* Form Handling
*/
const handleInput = (e) => {
e.preventDefault()
e.stopPropagation()
// reference the text input from the form
const textEl = e.target[0]
// change app's state and rerender
todos.push(textEl.value)
render()
// reset input
textEl.value = ''
textEl.focus()
}
document
.querySelector('#todos form')
.addEventListener('submit', handleInput)
/**
* Run the first rendering loop
* kinda "start the app" - kinda
*/
render()
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.