<div id="todos">
<form method="post" action="/my-backend-script">
<input type="text" placeholder="What's next?" />
<input type="submit" value="Add" />
</form>
<ul>
<li>Item n.1</li>
<li>Item n.2</li>
</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"] {
display: none;
text-transform: uppercase;
}
#todos form input[type="submit"]:active {
border-color: #369;
background-color: #369;
color: #fff;
}
/*
By adding a simple "is-valid" class to the
Todo's FORM - that wraps all the other
components - then we can easily fix the
style to display a "ready to sent" UI.
It's Javascript that implements the logic
to add or remove the "is-valid" class.
*/
#todos form.is-valid input[type="submit"] {
display: block;
}
#todos form.is-valid input[type="text"] {
margin-right: 10px;
}
/**
* 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;
}
/**
* Utility Functions
*/
const getTodosForm = () =>
document
.querySelector('#todos form')
const getTodosInput = () =>
document
.querySelector('#todos input[type="text"]')
const getTodosList = () =>
document
.querySelector('#todos ul')
const getTodosItems = () =>
document
.querySelectorAll('#todos li')
const getMessage = () =>
getTodosInput().value
const messageIsValid = text =>
text.length > 0
const cancelEvent = (event) => {
event.preventDefault()
event.stopPropagation()
}
const resetTodosInput = () => {
const input = getTodosInput()
input.value = ''
input.focus()
}
const removeNode = event =>
event.target.remove()
const addDeleteListener = node =>
node.addEventListener('click', removeNode)
/**
* App's Logic
*/
const checkStatus = () => {
const classList = getTodosForm().classList
const message = getMessage()
messageIsValid(message)
? classList.add('is-valid')
: classList.remove('is-valid')
}
const appendMessage = (message) => {
const textEl = document.createTextNode(message)
const itemEl = document.createElement('li')
itemEl.appendChild(textEl)
// Add the event listener for every
// dynamically generated item
addDeleteListener(itemEl)
getTodosList().appendChild(itemEl)
}
const onSubmit = (evt) => {
cancelEvent(evt)
const message = getMessage()
messageIsValid && appendMessage(message)
resetTodosInput()
}
// Setup the chat status listener
const inputEl = getTodosInput()
inputEl.addEventListener('input', checkStatus)
inputEl.addEventListener('change', checkStatus)
checkStatus()
// Setup the submit listener
const formEl = getTodosForm()
formEl.addEventListener('submit', onSubmit)
// Handle items that exist at boot time
const items = getTodosItems()
items.forEach(addDeleteListener)
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.