Confirm в ToDo App
Есть простое ToDo App. В том случае, если пользователь ввёл уже существующую в списке дел запись, интерфейс ToDo скрывается и появляется кастомный конфирм с возможностью выбора - добавить повторно или отказаться, все это осуществляется функцией toggleHiden, которая меняет класс "none" на "block" и наоборот. Проблема такая-как применить к кнопке "Да" функцию "createLi", которая создает дело, если пользователь соглашается добавить существующую запись и toggleHidden, чтобы снова вернуть интерфейс.
let task = document.querySelector('.inputName').value;
const addBtn = document.getElementById('addBtn');
const toDoList = document.querySelector('.toDoList');
const alertList = document.querySelector('.alert');
const formToDo = document.querySelector('.formToDo');
const yesBtn = document.getElementById('Yes');
const noBtn = document.getElementById('No');
function addToList() {
task = document.querySelector('.inputName').value;
if (task === '') {
alert('Напишите что-нибудь!');
} else {
let alerts = true;
let elementChildrens = toDoList.children;
for (let i = 0, child; child = elementChildrens[i]; i++) {
if (task === child.textContent) {
alerts = false;
break;
}
}
function toggleHiden() {
alertList.style.display = (alertList.style.display == 'block') ? 'none' : 'block';
formToDo.style.display = (formToDo.style.display == 'none') ? 'block' : 'none';
toDoList.style.display = (toDoList.style.display == 'none') ? 'block' : 'none';
}
function createLi() {
let l1 = document.createElement('li');
l1.setAttribute('tabindex', 2)
l1.innerHTML = '<li></li>';
l1.classList.add('toDo');
l1.textContent = task;
toDoList.appendChild(l1);
document.querySelector('.inputName').value = '';
}
if (alerts) {
createLi();
} else {
toggleHiden();
yesBtn.addEventListener('click', createLi);
noBtn.addEventListener('click', toggleHiden)
document.querySelector('.inputName').value = '';
}
}
}
addBtn.addEventListener('click', addToList);
html,
body {
padding: 0;
min-width: 1000px;
font-family: Arial;
background-color: #f9f9f9 !important;
}
.container {
position: relative;
}
.wrapper {
display: flex;
justify-content: center;
}
.formToDo {
margin: 100px;
flex: 0 0 50%;
padding: 0 40px 40px;
display: flex;
flex-direction: column;
background-color: rgba(255, 255, 255, 0.85);
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
}
.heading {
padding: 25px 25px;
text-align: center;
font-size: 30px;
}
.hiden {
display: none;
}
.through {
background: #888;
text-decoration: line-through;
}
.toDo {
padding: 5px 0;
cursor: pointer;
background: #eee;
transition: 0.2s;
}
.toDoList {
padding-left: 15px;
}
.inputName {
width: 100%;
margin-bottom: 30px;
}
/* Установить все нечетные элементы списка в другой цвет (зебра) */
.toDo:nth-child(odd) {
background: #f9f9f9;
}
/* Более темный фон-цвет при наведении */
.toDo:hover {
background: #ddd;
}
.btn {
align-self: flex-end;
}
.alert {
margin-top: 250px;
padding: 25px;
background-color: rgba(255, 255, 255, 0.85);
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
}
.close {
padding-right: 10px;
}
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Список дел</title>
<link rel="stylesheet" href="styles.css" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" />
<script src="script.js" defer></script>
</head>
<body>
<div class="container">
<div class="wrapper">
<div class="formToDo">
<h1 class="heading">Мой список дел:</h1>
<input type="text" class="inputName form-control" placeholder="Напишите..." tabindex="1"/>
<ol class="toDoList">
<li class="toDo" tabindex="2">Сходить в магазин</li>
<li class="toDo" tabindex="2">Приготовить ужин</li>
</ol>
<button type="submit" id="addBtn" class="btn btn-primary" tabindex="3">Добавить</button>
</div>
<div class="alert hiden">
Такая запись уже есть. Всё равно добавить?
<button id="Yes" class="btn btn-success">Да</button>
<button id="No" class="btn btn-danger">Нет</button>
</div>
</div>
</div>
</body>
</html>
Ответы (2 шт):
Автор решения: mr__scrpt
→ Ссылка
Как-то так:
const buttonYes = document.querySelector('.btn-success')
//через делегирование на документ
document.addEventListener('click', e =>{
if(e.target === buttonYes){
createLi()
}
})
Автор решения: Sergei Kirjanov
→ Ссылка
Зарефакторил. Если есть вопросы, почему что-то как-то сделано -- пишите.
const toDoList = document.querySelector('.toDoList')
const newCaptionInput = document.querySelector('.inputName')
function hasSameText() {
return [...toDoList.children].some(child => newCaptionInput.value === child.textContent)
}
function showSameDialog(on) {
document.querySelector('.alert').style.display = on ? 'block' : 'none'
document.querySelector('.formToDo').style.display = on ? 'none' : 'block'
}
function createLi() {
const l1 = document.createElement('li')
l1.setAttribute('tabindex', 2)
l1.classList.add('toDo')
l1.textContent = newCaptionInput.value
toDoList.appendChild(l1)
newCaptionInput.value = ''
}
function addToList() {
task = document.querySelector('.inputName').value;
if (task === '') alert('Напишите что-нибудь!');
else if (!hasSameText()) createLi()
else showSameDialog(true)
}
document.getElementById('Yes').addEventListener('click', ev => {
showSameDialog(false)
createLi()
})
document.getElementById('No').addEventListener('click', ev => {
showSameDialog(false)
})
document.getElementById('addBtn').addEventListener('click', ev => addToList())
html,
body {
padding: 0;
min-width: 1000px;
font-family: Arial;
background-color: #f9f9f9 !important;
}
.container {
position: relative;
}
.wrapper {
display: flex;
justify-content: center;
}
.formToDo {
margin: 100px;
flex: 0 0 50%;
padding: 0 40px 40px;
display: flex;
flex-direction: column;
background-color: rgba(255, 255, 255, 0.85);
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
}
.heading {
padding: 25px 25px;
text-align: center;
font-size: 30px;
}
.hiden {
display: none;
}
.through {
background: #888;
text-decoration: line-through;
}
.toDo {
padding: 5px 0;
cursor: pointer;
background: #eee;
transition: 0.2s;
}
.toDoList {
padding-left: 15px;
}
.inputName {
width: 100%;
margin-bottom: 30px;
}
/* Установить все нечетные элементы списка в другой цвет (зебра) */
.toDo:nth-child(odd) {
background: #f9f9f9;
}
/* Более темный фон-цвет при наведении */
.toDo:hover {
background: #ddd;
}
.btn {
align-self: flex-end;
}
.alert {
margin-top: 250px;
padding: 25px;
background-color: rgba(255, 255, 255, 0.85);
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
}
.close {
padding-right: 10px;
}
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Список дел</title>
<link rel="stylesheet" href="styles.css" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" />
<script src="script.js" defer></script>
</head>
<body>
<div class="container">
<div class="wrapper">
<div class="formToDo">
<h1 class="heading">Мой список дел:</h1>
<input type="text" class="inputName form-control" placeholder="Напишите..." tabindex="1"/>
<ol class="toDoList">
<li class="toDo" tabindex="2">Сходить в магазин</li>
<li class="toDo" tabindex="2">Приготовить ужин</li>
</ol>
<button type="submit" id="addBtn" class="btn btn-primary" tabindex="3">Добавить</button>
</div>
<div class="alert hiden">
Такая запись уже есть. Всё равно добавить?
<button id="Yes" class="btn btn-success">Да</button>
<button id="No" class="btn btn-danger">Нет</button>
</div>
</div>
</div>
</body>
</html>
Дальше мой вариант на React. Кода сильно меньше, и развивать проще.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Список дел</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" />
<style>
html,
body {
padding: 0;
min-width: 1000px;
font-family: Arial;
background-color: #f9f9f9 !important;
}
.container {
position: relative;
}
.wrapper {
display: flex;
justify-content: center;
}
.formToDo {
margin: 100px;
flex: 0 0 50%;
padding: 0 40px 40px;
display: flex;
flex-direction: column;
background-color: rgba(255, 255, 255, 0.85);
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
}
.heading {
padding: 25px 25px;
text-align: center;
font-size: 30px;
}
.hiden {
display: none;
}
.through {
background: #888;
text-decoration: line-through;
}
.toDo {
padding: 5px 0;
cursor: pointer;
background: #eee;
transition: 0.2s;
}
.toDoList {
padding-left: 15px;
}
.inputName {
width: 100%;
margin-bottom: 30px;
}
/* Установить все нечетные элементы списка в другой цвет (зебра) */
.toDo:nth-child(odd) {
background: #f9f9f9;
}
/* Более темный фон-цвет при наведении */
.toDo:hover {
background: #ddd;
}
.btn {
align-self: flex-end;
}
.alert {
margin-top: 250px;
padding: 25px;
background-color: rgba(255, 255, 255, 0.85);
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
}
.close {
padding-right: 10px;
}
</style>
</head>
<body>
<div class="calcContainer"></div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
const { useState } = React
const initItems = () => [
{ caption: "Сходить в магазин", key: 1 },
{ caption: "Приготовить ужин", key: 2 },
]
const useTodoList = () => {
const [ newCaption, setNewCaption ] = useState("")
const [ items, setItems ] = useState(initItems)
const addItem = newCaption.length <= 0 ? null : () => {
setItems(cItems=>[...cItems,{ caption: newCaption, key: Date.now() }])
setNewCaption("")
}
const sameCaptionFound = items.some(item => item.caption === newCaption)
return { items, addItem, newCaption, setNewCaption, sameCaptionFound }
}
const App = () =>{
const { items, addItem, newCaption, setNewCaption, sameCaptionFound } = useTodoList()
return (
<div className="container">
<div className="wrapper">
<div className="formToDo">
<h1 className="heading">Мой список дел:</h1>
<input type="text" className="inputName form-control" placeholder="Напишите..." tabIndex="1" value={newCaption} onChange={ev => setNewCaption(ev.target.value)} />
<ol className="toDoList">
{items.map(item=>(
<li className="toDo" tabIndex="2" key={item.key}>{item.caption}</li>
))}
</ol>
{!addItem && <span>Введите что-то</span>}
{sameCaptionFound && <span>Такая запись уже есть</span>}
<button type="submit" id="addBtn" className="btn btn-primary" tabIndex="3" onClick={ev=>addItem()} disabled={addItem?undefined:true}>Добавить</button>
</div>
</div>
</div>
)
}
ReactDOM.render(<App/>, document.querySelector('.calcContainer'))
</script>
</body>
</html>