JS Fiddle - приложение Todo
При создании приложений, в которых необходимо динамически вставлять похожие элементы и отслеживать их с помощью системы ID, я рекомендую более организованный подход, чтобы избежать путаницы в вашем коде.
Для базовых c приложений вы можете создавать собственные классы, каждый из которых имеет методы element
, template
, ui
, uiEventCallbacks
, toggleUIEvents
и render
. В каждом классе element
будет основным элементом HTML, который содержит разметку template
. Метод render
анализирует текст template
и присваивает его element.innerHTML
. Чтобы создать экземпляр приложения, просто создайте новый экземпляр базового класса, отобразите его, а затем добавьте элемент в тело.
Я создал приложение Todo с вашей разметкой. Есть классы TodoApp
, Todos
и Todo
. TodoApp
содержит Todos
, а Todos
содержит экземпляры Todo
.
Todo
const Todo = class {
constructor(settings) {
this.settings = settings
}
get settings() { return this._settings }
set settings(settings) { this._settings = settings }
get element() {
if(!this._element) {
this._element = document.createElement('li')
this._element.setAttribute('class', 'list-item')
this._element.setAttribute('id', this.settings.id )
}
return this._element
}
get ui() { return {
deleteButton: this.element.querySelectorAll(':scope > .delete-btn'),
} }
get uiEventCallbacks() { return {
deleteButtonClick: (event) => {
let customEvent = new CustomEvent('removeTodo', {
bubbles: true,
details: {
id: this.settings.id
}
})
this.element.dispatchEvent(
customEvent
)
},
} }
remove() {
this.element.parentElement.removeChild(this.element)
}
template() { return `
<span>${this.settings.value}</span>
<button class="delete-btn">Delete</button>
` }
toggleUIEvents() {
[
'removeEventListener',
'addEventListener'
].forEach((eventMethod) => {
this.ui.deleteButton.item(0)[eventMethod]('click', this.uiEventCallbacks.deleteButtonClick)
})
}
render() {
const template = this.template()
this.element.innerHTML = template
this.toggleUIEvents()
return this
}
}
Todos
const Todos = class {
constructor() {}
get element() {
if(!this._element) {
this._element = document.createElement('section')
this._element.setAttribute('class', 'task-list')
}
return this._element
}
get ui() { return {
itemLog: this.element.querySelectorAll('.item-log')
} }
get uiEventCallbacks() { return {
removeTodo: (event) => {
console.log(event)
this.removeTodo()
},
} }
get todos() {
this._todos = this._todos || []
return this._todos
}
template() { return `
<h2>Task List</h2>
<div class="list-wrap">
<ul class="item-log"></ul>
</div>
` }
toggleUIEvents() {
[
'removeEventListener',
'addEventListener'
].forEach((eventMethod) => {
this.ui.itemLog.item(0)[eventMethod]('removeTodo', this.uiEventCallbacks.removeTodo)
})
}
addTodo(data) {
const todo = new Todo(data)
this.todos.push(todo)
this.ui.itemLog.item(0).appendChild(
todo.render().element
)
return this
}
removeTodo(id) {
let todoIndex = this.todos.reduce((_todoIndex, todo, todoIndex) => {
if(todo.id === id) _todoIndex = todoIndex
return _todoIndex
}, -1)
let todo = this.todos.splice(todoIndex, 1)[0]
todo.remove()
return this
}
render(data) {
const template = this.template(data)
this.element.innerHTML = template
this.toggleUIEvents()
return this
}
}
Приложение Todo
const TodoApp = class {
constructor() {}
get element() {
if(!this._element) {
this._element = document.createElement('main')
}
return this._element
}
get ui() { return {
addButton: this.element.querySelectorAll('.add-btn'),
input: this.element.querySelectorAll('.task-field'),
} }
get uiEventCallbacks() { return {
addTodo: (event) => {
let taskFieldData = this.ui.input.item(0).value
this.todos.addTodo({
id: this.uuid(),
value: taskFieldData,
})
},
} }
get todos() {
this._todos = this._todos || new Todos()
return this._todos
}
uuid() {
var uuid = '', i, random
for (i = 0; i < 32; i++) {
random = Math.random() * 16 | 0
if (i === 8 || i === 12 || i === 16 || i === 20) {
uuid += "-"
}
uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16)
}
return uuid
}
template() { return `
<div class="entry-field">
<label class="task-input" for="task-input">Task:</label>
<input type="text" class="task-field" placeholder="Enter Item"/>
<button class="add-btn">ADD</button>
</div>
` }
toggleUIEvents() {
[
'removeEventListener',
'addEventListener'
].forEach((eventMethod) => {
this.ui.addButton.item(0)[eventMethod]('click', this.uiEventCallbacks.addTodo)
})
}
render(data) {
const template = this.template(data)
this.element.innerHTML = template
this.element.appendChild(this.todos.render().element)
this.toggleUIEvents()
return this
}
}
Создание экземпляра приложения Todo
const todoApp = new TodoApp()
const body = document.querySelector('body')
body.insertAdjacentElement('afterbegin', todoApp.render().element)