I am building a basic CRUD app and I am using Firebase for my backend. I have implemented the create and read functionality, but I am having problems with the delete method. The results are shown from my database in a html table and after each result there is a delete button, however when you click on the delete button, firebase gives me this error: Uncaught Error: Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: null
Why, what am I doing wrong?
here is my js:
const animalList = document.querySelector('#animal-list');
const form = document.querySelector('#add-animals');
function renderAnimals(doc) {
let tr = document.createElement('tr');
let td = document.createElement('td');
let deleteButton = document.createElement('button');
let editButton = document.createElement('button')
// Animal properties
let name = document.createElement('div');
let species = document.createElement('div');
let age = document.createElement('div');
let last_fed = document.createElement('div');
let last_shed = document.createElement('div');
let diet = document.createElement('div');
let basking_area_temp = document.createElement('div');
let cold_part_temp = document.createElement('div');
let humidity = document.createElement('div');
let additional_info = document.createElement('div');
// Edit Form inputs and buttons
let editForm = document.createElement('form');
let submit = document.createElement('input');
let nameInput = document.createElement('input');
let speciesInput = document.createElement('input');
let ageSpecies = document.createElement('input');
let lastFedInput = document.createElement('input');
let lastShedInput = document.createElement('input');
let dietInput = document.createElement('input');
let baskingAreaTempInput = document.createElement('input');
let coldPartTempInput = document.createElement('input');
let humidityInput = document.createElement('input');
let additionalInfoInput = document.createElement('input');
// Edit modal creation
let modal = document.createElement('div');
let modalDialog = document.createElement('div');
let modalContent = document.createElement('div');
let span = document.createElement('span');
let h2 = document.createElement('h2');
let nameLabel = document.createElement('label');
let speciesLabel = document.createElement('label');
let ageLabel = document.createElement('label');
let lastFedLabel = document.createElement('label');
let lastShedLabel = document.createElement('label');
let dietLabel = document.createElement('label');
let baskingAreaTempLabel = document.createElement('label');
let coldPartTempLabel = document.createElement('label');
let humidityLabel = document.createElement('label');
let additionalInfoLabel = document.createElement('label');
// Class and data setting
tr.setAttribute('data-id', doc.id);
name.textContent = `name: ${doc.data().name}`;
deleteButton.textContent = 'Delete';
deleteButton.setAttribute('class','btn btn-danger');
editButton.textContent = 'Edit';
editButton.setAttribute('class', 'btn btn-info');
editForm.setAttribute('class', 'form-group');
modal.setAttribute('id','editModal');
modal.setAttribute('class','modal ');
modal.setAttribute('tabindex', '-1');
modalDialog.setAttribute('class', 'modal-dialog');
modalContent.setAttribute('class','modal-content container');
span.textContent = 'X';
span.setAttribute('class','close');
h2.textContent = 'Edit Animal';
speciesLabel.innerHTML = 'Species:';
nameLabel.innerHTML = 'Name:';
ageLabel.textContent = 'Age:';
lastFedLabel.textContent='Last Fed:';
lastShedLabel.textContent= 'Last Shed:';
dietLabel.textContent = 'Diet:';
baskingAreaTempLabel.textContent = 'Basking temps';
coldPartTempLabel.textContent = 'Cold Part Temps';
humidityLabel.textContent = 'Humidity';
additionalInfoInput.textContent = 'Additional Info';
species.textContent = `species: ${doc.data().species}`;
age.textContent = `age: ${doc.data().age}`;
last_fed.textContent = `last fed: ${doc.data().last_fed}`;
last_shed.textContent = `last shed: ${doc.data().last_shed}`;
diet.textContent = `diet: ${doc.data().diet}`;
basking_area_temp.textContent =`basking area temp: ${ doc.data().basking_area_temp}`;
cold_part_temp.textContent = `cold part temp: ${doc.data().cold_part_temp}`;
humidity.textContent = `humidity: ${doc.data().humidity}`;
additional_info.textContent = `additional info: ${doc.data().additional_info}`;
editForm.setAttribute('method',"post");
editForm.setAttribute('action',"#");
editForm.setAttribute('class','edit-form');
submit.setAttribute('type',"submit");
submit.setAttribute('value',"Update");
submit.setAttribute('class',"btn btn-success");
nameLabel.setAttribute('for','name');
speciesLabel.setAttribute('for','name');
ageLabel.setAttribute('for','name');
lastFedLabel.setAttribute('for','');
lastShedLabel.setAttribute('for','last shed');
dietLabel.setAttribute('for','diet');
nameInput.setAttribute('class','form-control')
speciesInput.setAttribute('class','form-control');
ageSpecies.setAttribute('class','form-control');
lastFedInput.setAttribute('class','form-control');
lastShedInput.setAttribute('class','form-control');
baskingAreaTempInput.setAttribute('class','form-control');
coldPartTempInput.setAttribute('class','form-control');
humidityInput.setAttribute('class','form-control');
additionalInfoInput.setAttribute('class','form-control');
speciesInput.setAttribute('class','form-control');
dietInput.setAttribute('class','form-control');
//Visualizing the table
td.appendChild(species);
td.append(age);
td.append(last_fed);
td.append(last_shed);
td.append(diet);
td.append(basking_area_temp);
td.append(cold_part_temp);
td.append(humidity);
td.append(additional_info);
td.append(deleteButton);
td.append(editButton);
td.appendChild(nameInput);
td.append(ageSpecies);
td.append(lastFedInput);
td.append(lastShedInput);
td.append(dietInput);
td.append(baskingAreaTempInput);
td.append(coldPartTempInput);
td.append(humidityInput);
// td.append(additionalInfoInput);
td.append(speciesInput);
tr.appendChild(td);
editForm.append(nameLabel);
editForm.appendChild(nameInput);
editForm.append(ageLabel);
editForm.append(ageSpecies);
editForm.append(lastFedLabel);
editForm.append(lastFedInput);
editForm.append(lastShedLabel);
editForm.append(lastShedInput);
editForm.append(dietLabel);
editForm.append(dietInput);
editForm.append(baskingAreaTempLabel);
editForm.append(baskingAreaTempInput);
editForm.append(coldPartTempLabel);
editForm.append(coldPartTempInput);
editForm.append(humidityLabel);
editForm.append(humidityInput);
editForm.append(additionalInfoLabel);
// editForm.append(additionalInfoInput);
editForm.append(speciesLabel);
editForm.append(speciesInput);
editForm.append(submit);
td.append(editForm);
tr.appendChild(td);
modal.append(modalDialog);
modalDialog.append(modalContent);
modalContent.append(span);
modalContent.append(h2);
td.append(modal);
modalContent.append(editForm);
animalList.appendChild(tr);
// Firebase operations
//deleting data
deleteButton.addEventListener('click', (event) => {
event.stopPropagation();
let id = event.target.parentElement.getAttribute('data-id');
db.collection('animals').doc(id).delete();
})
editButton.addEventListener('click', () => {
modal.style.display = 'flex';
})
span.addEventListener('click', () => {
modal.style.display = "none";
})
}
// getting data from the back end
db.collection('animals').onSnapshot(snapshot => {
let changes = snapshot.docChanges();
changes.forEach(change => {
if(change.type == 'added') {
renderAnimals(change.doc);
} else if (change.type == 'removed') {
let li = animalList.querySelector('[data-id=' + change.doc.id + ']');
animalList.removeChild(li);
}
})
})
// adding data
form.addEventListener('submit', (event) => {
event.preventDefault();
db.collection('animals').add({
species: form.species.value,
name: form.name.value,
age: form.age.value,
last_fed: document.querySelector('#last-fed').value,
last_shed: document.querySelector('#last-shed').value,
diet: form.diet.value,
basking_area_temp: document.querySelector('#basking-area-temperature').value,
cold_part_temp: document.querySelector('#cold-temperature').value,
humidity: form.humidity.value,
additional_info: document.querySelector('#additional-info').value
})
})
and my html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Repti Care</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://www.gstatic.com/firebasejs/5.5.7/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.5.5/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.5.5/firebase-firestore.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"
integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<link rel="stylesheet" href="./css/main.css">
</head>
<body>
<div class="jumbotron">
<div class="placeholder"></div>
</div>
<div class="container">
<h2>Add a new Animal</h2>
<form class="form-group" id="add-animals">
Species: <input type="text" id="species" class="form-control">
Name: <input type="text" id="name" class="form-control" >
Age: <input type="text" id="age" class="form-control">
Last Fed: <input type="date" id="last-fed" class="form-control">
Last Shed: <input type="date" id="last-shed" class="form-control">
Diet: <input type="text" id="diet" class="form-control">
Basking area temperature: <input type="text" id="basking-area-temperature" class="form-control">
Cold part temperature: <input type="text" id="cold-temperature" class="form-control">
Humidity: <input type="text" id="humidity" class="form-control">
Addition Info: <textarea class="form-control" id="additional-info"></textarea>
<button id="btnCreate" class="btn btn-primary">Create</button>
</form>
<h3>View Current Animals</h3>
<table id="animal-list">
<th>Animals</th>
</table>
</div>
</div>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyBSuC8nqJzLe7d5jKS-_nE15kaI9Y6NIfI",
authDomain: "repti-care-32176.firebaseapp.com",
databaseURL: "https://repti-care-32176.firebaseio.com",
projectId: "repti-care-32176",
storageBucket: "repti-care-32176.appspot.com",
messagingSenderId: "632910932105"
};
firebase.initializeApp(config);
const db = firebase.firestore();
db.settings({ timestampsInSnapshots: true });
</script>
<script
src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous"></script>
<script src="./scripts/main.js"></script>
</body>
</html>
I tried looking up the error and reading firebase documentation but I could not find anything.
The immediate problem is that you attempt to set the data-id property on a <tr> element, but try to read it from a <td> element inside that <tr>. See:
tr.setAttribute('data-id', doc.id);
...
td.append(deleteButton);
...
tr.appendChild(td);
...
let id = event.target.parentElement.getAttribute('data-id');
So the parent will not be your tr but the directly enclosing td.
The error message is telling you that you passed an invalid value to the doc() method here:
db.collection('animals').doc(id).delete();
You need to debug your code and figure out why id is null or undefined.
Related
There is a quest I've been trying to solve for quite a time.
In my code, I have a "To-Do List".
And there, I want to make the buttons ("doneButton", "deleteButton") workable with "addEventListener".
Somehow, the buttons don't work as expected.
When I run this within the code console.log(todoItem.doneButton), it shows the correct button.
But just the line below, where I try to "addEventListener" to the same very element, it doesn't work at all.
(function() {
function createAppTitle(title) {
let appTitle = document.createElement('h2');
appTitle.textContent = title;
appTitle.classList.add('mt-5', 'mb-3');
return appTitle;
}
function createToDoList() {
let list = document.createElement('ul')
return list;
}
function createToDoForm() {
let buttonWrapper = document.createElement('div')
let form = document.createElement('form')
let input = document.createElement('input')
let button = document.createElement('button')
form.classList.add('input-group', 'mb-3');
input.classList.add('form-control');
input.placeholder = 'Enter the name of the task';
buttonWrapper.classList.add('input-group-append');
button.classList.add('btn', 'btn-primary');
button.textContent = 'Add a task';
buttonWrapper.append(button);
form.append(input);
form.append(buttonWrapper);
return {
form,
input,
button
};
}
function createToDoItem (name) {
let item = document.createElement('li')
let buttonGroup = document.createElement('div')
let doneButton = document.createElement('button')
let deleteButton = document.createElement('button')
item.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'align-items-center');
item.textContent = name;
buttonGroup.classList.add('btn-group','btn-group-sm');
doneButton.classList.add('btn','btn-success');
doneButton.textContent = "Done";
deleteButton.classList.add('btn','btn-danger');
deleteButton.textContent = 'Delete';
buttonGroup.append(doneButton);
buttonGroup.append(deleteButton);
item.append(buttonGroup);
return {
item,
doneButton,
deleteButton
}
}
document.addEventListener('DOMContentLoaded', function () {
let container = document.querySelector('.container');
let appTitle = createAppTitle('Name of the Target');
let list = createToDoList();
let form = createToDoForm();
let todoItems = [createToDoItem('Book your trip'), createToDoItem('Fly to Dubai'), createToDoItem('Book' +
' your trip')];
container.append(appTitle);
container.append(form.form);
container.append(list);
list.append(todoItems[0].item)
list.append(todoItems[1].item)
list.append(todoItems[2].item)
form.form.addEventListener('submit', (e)=> {
e.preventDefault();
if (!form.input.value) {
return;
}
let todoItem = createToDoItem(form.input.value);
console.log(todoItem.doneButton)
todoItem.doneButton.addEventListener('click', function () {
console.log('done button clicked');
});
todoItem.deleteButton.addEventListener('click', ()=> {
console.log('delete button clicked');
})
list.append(createToDoItem(form.input.value).item)
form.input.value = '';
});
})
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ToDo</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
crossorigin="anonymous">
<script src="index.js" defer></script>
</head>
<body>
<div id="toDo" class="container"></div>
</body>
</html>
You should attach the event inside the createToDoItem()
(function() {
function createAppTitle(title) {
let appTitle = document.createElement('h2');
appTitle.textContent = title;
appTitle.classList.add('mt-5', 'mb-3');
return appTitle;
}
function createToDoList() {
let list = document.createElement('ul')
return list;
}
function createToDoForm() {
let buttonWrapper = document.createElement('div')
let form = document.createElement('form')
let input = document.createElement('input')
let button = document.createElement('button')
form.classList.add('input-group', 'mb-3');
input.classList.add('form-control');
input.placeholder = 'Enter the name of the task';
buttonWrapper.classList.add('input-group-append');
button.classList.add('btn', 'btn-primary');
button.textContent = 'Add a task';
buttonWrapper.append(button);
form.append(input);
form.append(buttonWrapper);
return {
form,
input,
button
};
}
function createToDoItem (name) {
let item = document.createElement('li')
let buttonGroup = document.createElement('div')
let doneButton = document.createElement('button')
let deleteButton = document.createElement('button')
item.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'align-items-center');
item.textContent = name;
buttonGroup.classList.add('btn-group','btn-group-sm');
doneButton.classList.add('btn','btn-success');
doneButton.textContent = "Done";
deleteButton.classList.add('btn','btn-danger');
deleteButton.textContent = 'Delete';
buttonGroup.append(doneButton);
buttonGroup.append(deleteButton);
item.append(buttonGroup);
doneButton.addEventListener('click', function () {
console.log('done button clicked');
});
deleteButton.addEventListener('click', ()=> {
console.log('delete button clicked');
})
return {
item,
doneButton,
deleteButton
}
}
document.addEventListener('DOMContentLoaded', function () {
let container = document.querySelector('.container');
let appTitle = createAppTitle('Name of the Target');
let list = createToDoList();
let form = createToDoForm();
let todoItems = [createToDoItem('Book your trip'), createToDoItem('Fly to Dubai'), createToDoItem('Book' +
' your trip')];
container.append(appTitle);
container.append(form.form);
container.append(list);
list.append(todoItems[0].item)
list.append(todoItems[1].item)
list.append(todoItems[2].item)
form.form.addEventListener('submit', (e)=> {
e.preventDefault();
if (!form.input.value) {
return;
}
let todoItem = createToDoItem(form.input.value);
console.log(todoItem.doneButton)
list.append(createToDoItem(form.input.value).item)
form.input.value = '';
});
})
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ToDo</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
crossorigin="anonymous">
<script src="index.js" defer></script>
</head>
<body>
<div id="toDo" class="container"></div>
</body>
</html>
How can I fix the function to delete all todoItems? My guess is that the for loops is not working right :\ I appreciate any help with my problem! I have only 1-month of experience with javascript.
How can I fix the function to delete all todoItems? My guess is that the for loops is not working right :\ I appreciate any help with my problem! I have only 1-month of experience with javascript.
function selectColorStatus(event){
let target = event.target;
target.classList.toggle('todoTextSelected');
}
function createToDoItem(userInputValue){
// To-Do Item Container
let todoItem = document.createElement("div");
todoItem.classList.add("row", "flx");
todoItem.onclick = selectColorStatus;
// Clear List
let btnDeleteItem = document.getElementById('btnDeleteItem');
btnDeleteItem.onclick = function (){
for(let i = 0; i < todoItem; i++){
todoItem.remove();
}
}
// Inner Text
let todoText = document.createElement('div');
todoText.classList.add('grow');
todoText.innerText = userInputValue;
// Date
let CreateDate = document.createElement('div');
CreateDate.classList.add('date');
let date = new Date();
year = date.getFullYear();
month = date.getMonth();
day = date.getDay();
CreateDate.innerText = 'Created at ' + year + '-' + month + '-'+ day;
// Delete Button
let deleteBtn = document.createElement('div');
deleteBtn.classList.add('btnDelete');
deleteBtn.innerText = 'X';
deleteBtn.onclick = function(){
todoItem.remove();
}
todoItem.appendChild(todoText);
todoItem.appendChild(CreateDate)
todoItem.appendChild(deleteBtn);
let todoItemsContainer = document.getElementById('todoItemsContainer');
todoItemsContainer.appendChild(todoItem);
}
// Item Entry and Validation
function ToDoItemHandler(){
let userInput = document.getElementById('toDoEntry');
let userInputValue = userInput.value;
if(userInputValue == ''){
alert('Entry can not be empty!')
}else{
createToDoItem(userInputValue);
userInput.value = '';
}
}
// Add Item Button
let btnAddItem = document.getElementById('btnAddItem');
btnAddItem.onclick = ToDoItemHandler;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href = './style/style.css' rel='stylesheet'>
<title>To-Do-List</title>
</head>
<body>
<div id = 'container'>
<div id="toDoHeader">
<h1>To-Do List</h1>
<div id = 'toDoContent'>
<input type = 'text' id = 'toDoEntry' name = 'toDoEntry' placeholder = 'Add item here'>
<button type = 'button' id = 'btnAddItem' name = 'addToDoList'>Add</button>
<button type = 'button' id = 'btnDeleteItem' name = 'deleteList'>Delete All</button>
</div>
</div>
<div id="todoItemsContainer">
</div>
</div>
<script src = './js/app.js'></script>
</body>
</html>
Change your delete function to
let btnDeleteItem = document.getElementById('btnDeleteItem');
btnDeleteItem.onclick = function (){
const items = document.querySelectorAll('.row') // select all todos
items.forEach(el => {
el.remove() // remove each one
})
}
function selectColorStatus(event) {
let target = event.target;
target.classList.toggle('todoTextSelected');
}
function createToDoItem(userInputValue) {
// To-Do Item Container
let todoItem = document.createElement("div");
todoItem.classList.add("row", "flx");
todoItem.onclick = selectColorStatus;
// Clear List
let btnDeleteItem = document.getElementById('btnDeleteItem');
btnDeleteItem.onclick = function () {
const items = document.querySelectorAll('.row')
items.forEach(el => {
el.remove()
})
}
// Inner Text
let todoText = document.createElement('div');
todoText.classList.add('grow');
todoText.innerText = userInputValue;
// Date
let CreateDate = document.createElement('div');
CreateDate.classList.add('date');
let date = new Date();
year = date.getFullYear();
month = date.getMonth();
day = date.getDay();
CreateDate.innerText = 'Created at ' + year + '-' + month + '-' + day;
// Delete Button
let deleteBtn = document.createElement('div');
deleteBtn.classList.add('btnDelete');
deleteBtn.innerText = 'X';
deleteBtn.onclick = function () {
todoItem.remove();
}
todoItem.appendChild(todoText);
todoItem.appendChild(CreateDate)
todoItem.appendChild(deleteBtn);
let todoItemsContainer = document.getElementById('todoItemsContainer');
todoItemsContainer.appendChild(todoItem);
}
// Item Entry and Validation
function ToDoItemHandler() {
let userInput = document.getElementById('toDoEntry');
let userInputValue = userInput.value;
if (userInputValue == '') {
alert('Entry can not be empty!')
} else {
createToDoItem(userInputValue);
userInput.value = '';
}
}
// Add Item Button
let btnAddItem = document.getElementById('btnAddItem');
btnAddItem.onclick = ToDoItemHandler;
<div id = 'container'>
<div id="toDoHeader">
<h1>To-Do List</h1>
<div id = 'toDoContent'>
<input type ='text' id='toDoEntry' name ='toDoEntry' placeholder = 'Add item here'>
<button type ='button' id='btnAddItem' name ='addToDoList'>Add</button>
<button type ='button' id='btnDeleteItem' name ='deleteList'>Delete All</button>
</div>
</div>
<div id="todoItemsContainer">
</div>
</div>
simply do:
// Clear List
let btnDeleteItem = document.getElementById('btnDeleteItem');
btnDeleteItem.onclick = function () {
document.getElementById('todoItemsContainer').innerHTML = ''
}
{
document.addEventListener('DOMContentLoaded', () => {
const addTaskTrigger = document.getElementsByClassName('addTask-trigger')[0];
const addTaskTarget = document.getElementsByClassName('addTask-target')[0];
const addTaskValue = document.getElementsByClassName('addTask-value')[0];
const radioWork = document.getElementById('radio-work');
const radioDone = document.getElementById('radio-done');
let nextId = 0;
const todos = [];
//Taskとidを作成
const addTask = (task, id, tableItem) => {
const idSpanTd = document.createElement('td');
const taskSpanTd = document.createElement('td');
//タスク追加時にtodosにtodoを追加
const todo = {
task: 'taskSpanTd',
status: '作業中'
};
todos.push(todo);
//要素内のHTML文章を変更する
idSpanTd.innerText = id;
taskSpanTd.innerText = task;
//生成したテーブル要素をブラウザに表示する
tableItem.append(idSpanTd);
tableItem.append(taskSpanTd);
addTaskTarget.append(tableItem);
};
//Button要素を生成する
const addButton = (tableItem, removeButton, createButton) => {
const createButtonTd = document.createElement('td');
const removeButtonTd = document.createElement('td');
//要素内のHTML文章を変更する
createButton.innerText = '作業中';
removeButton.innerText = '削除';
//生成したテーブル要素をブラウザに表示する
tableItem.append(createButtonTd);
tableItem.append(removeButtonTd);
addTaskTarget.append(tableItem);
//生成したbutton要素を生成する
createButtonTd.append(createButton);
removeButtonTd.append(removeButton);
};
//Perform processing to add td element when clicking the add button
addTaskTrigger.addEventListener('click', () => {
const task = addTaskValue.value;
const tableItem = document.createElement('tr');
const removeButton = document.createElement('button');
const createButton = document.createElement('button');
addTask(task, nextId++, tableItem);
addButton(tableItem, removeButton, createButton);
addTaskValue.value = '';
// //削除ボタンを押した時にタスクを削除する
const deleteElement = (a) => {
const tableTag = a.target.closest('tr');
if (tableTag) tableTag.remove();
updateId();
}
removeButton.addEventListener('click', deleteElement, false);
//When you press the button, it changes from working to completion
createButton.addEventListener('click', (a) => {
if (createButton.textContent === "作業中") {
createButton.textContent = "完了";
const doneParent = a.target.parentNode;
doneParent.className = 'workDone';/*完了class*/
} else {
createButton.textContent = "作業中";
const workParent = a.target.parentNode;
workParent.className = 'work';/*作業中class*/
}
});
})
/*Processing when pressing the radio button in progress*/
radioDone.addEventListener('click', function () {
let workTasks = document.getElementsByClassName('work');
workTasks = Array.from(workTasks);
if (radioWork.checked === true) {
workTasks.forEach(function (workTasks) {
workTasks.style.display = "none";
})
} else {
workTasks.forEach(function (workTasks) {
workTasks.style.display = "none";
})
}
})
//Processing when radio button complete is pressed
radioWork.addEventListener('click', function () {
let doneTasks = document.getElementsByClassName('workDone');
doneTasks = Array.from(doneTasks);
if (radioDone.checked === true) {
doneTasks.forEach(function (doneTasks) {
doneTasks.style.display = "none";
})
} else {
doneTasks.forEach(function (doneTasks) {
doneTasks.style.display = "none";
})
}
})
// Serial number reassignment
const updateId = () => {
const tbody = document.getElementsByTagName("tbody")[0];
const taskList = tbody.getElementsByTagName('tr');
nextId = 0;
Array.from(taskList, tr => {
tr.getElementsByTagName('td')[0].textContent = nextId;
nextId++
});
}
});
}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/style.css">
<title>Todoリスト</title>
</head>
<body>
<h1>Todoリスト</h1>
<p>
<input type="radio" name="task" value="1" checked ="checked">全て
<input type="radio" id="radio-work" name="task" value="2">作業中
<input type="radio" id="radio-done" name="task" value="3">完了
</p>
<p></p>
<table>
<thead>
<th>ID</th>
<th>コメント</th>
<th>状態</th>
<th></th>
</thead>
<tbody class="addTask-target" id="tbody"></tbody>
</table>
<h2>新規タスクの追加</h2>
<input class="addTask-value" type="text" />
<button class="addTask-trigger" type="button">追加</button>
<script src="js/main.js"></script>
</body>
</html>
I am creating a Todo list and trying to implement it with the following contents.
https://gyazo.com/0b47106078622a1e44e912f56b5e9603
-Show/hide depending on task status
-Toggle task display depending on radio button selected
-If you add a new task when "Working" is selected, the task will be displayed
-If you add a new task when "Complete" is selected, the task will not be displayed (but it is added correctly in the background)
■ Current problems
(1) If you press the task completion button and then put the check box into operation, "Only the completion button" will be hidden.
→I want to hide every td
(2) Even if you click the in-process button and then click the completion check box, it will not be hidden
■ Tried
if (createButton.textContent === "Working") {
createButton.textContent = "Done";
const doneParent = a.target.parentNode;
doneParent.className ='workDone'; /* Done class */
Here is this.parentNode;
I changed it to
If you have any other problems, please let me know.
Thank you for your guidance.
Excuse the question.
I want to make a todo list like this.
https://gyazo.com/0dd4feeea3f7a27aefe6d2160944c65e
However, when I press the "Add button", the task goes to the right instead of going down.
In such cases, how should I implement it?
※As a condition, I want to separate addTask function and addButton function.
{
document.addEventListener('DOMContentLoaded', function() {
const addTaskTrigger = document.getElementsByClassName('addTask-trigger')[0];
const addTaskTarget = document.getElementsByClassName('addTask-target')[0];
const addTaskValue = document.getElementsByClassName('addTask-value')[0];
let nextId = 0;
const todos = [];
var tableItem = document.createElement('tr');
const addTask = (task, id) => {
let idSpanTd = document.createElement('td');
let taskSpanTd = document.createElement('td');
//要素内のHTML文章を変更する
idSpanTd.innerText = id;
taskSpanTd.innerText = task;
//生成したテーブル要素をブラウザに表示する
tableItem.append(idSpanTd);
tableItem.append(taskSpanTd);
addTaskTarget.append(tableItem);
return(task,id)
};
//Button要素を生成する
let removeButton = document.createElement('button');
let createButton = document.createElement('button');
const addButton = (button) => {
let createButtonTd = document.createElement('td');
let removeButtonTd = document.createElement('td');
//要素内のHTML文章を変更する
createButton.innerText = '作業中';
removeButton.innerText = '削除';
//生成したテーブル要素をブラウザに表示する
tableItem.append(createButtonTd);
tableItem.append(removeButtonTd);
addTaskTarget.append(tableItem);
//生成したbutton要素を生成する
createButtonTd.append(createButton);
removeButtonTd.append(removeButton);
return(button)
};
//追加ボタンをクリックした際にタスクを追加する処理を行う
addTaskTrigger.addEventListener('click', () => {
const task = addTaskValue.value;
addTask(task, nextId++);
addButton();
addTaskValue.value = '';
});
//チェックリスト用オブジェクト
const todo = {
task: 'taskSpanTd',
status: '作業中'
};
todos.push(todo);
removeButton.addEventListener('click', delete_element, false);
// //削除ボタンを押した時にタスクを削除する
function delete_element () {
let tabletag = this.closest ('tr');
if (tabletag)
tabletag.remove ();
}
});
}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel ="stylesheet" href="css/style.css">
<title>Todoリスト</title>
</head>
<body>
<h1>Todoリスト</h1>
<p>
<input type="radio" name="status" value="1" checked="checked">全て
<input type="radio" name="status" value="2">作業中
<input type="radio" name="status" value="3">完了
</p>
<p></p>
<table>
<thead>
<th>ID</th>
<th>コメント</th>
<th>状態</th>
<th></th>
</thead>
<tbody class ="addTask-target"></tbody>
</table>
<h2>新規タスクの追加</h2>
<input class="addTask-value" type="text" />
<button class="addTask-trigger" type="button">追加</button>
<script src="js/main.js"></script>
</body>
</script>
</html>
You have defined only one tableItem, only one removeButton and only one createButton.
You must define tableItem, removeButton and createButton as void variables, and only give them a value inside the addTaskTrigger.addEventListener('click') function. It would look like this:
addTaskTrigger.addEventListener('click', () => {
const task = addTaskValue.value;
// Must be already defined as variables
tableItem = document.createElement('tr');
removeButton = document.createElement('button');
createButton = document.createElement('button');
addTask(task, nextId++);
addButton();
addTaskValue.value = '';
});
You are defining only one event listener for each button (remove and create), but won't be enough for javascript to understand that it must listen to all of the rows' buttons. To do it the way you want, you must also define the eventListener only when the user adds a new task (you could define it inside the addButton() function, using the buttons IDs)
Just move creating elements (tableItem, removeButton, createButton, etc.) to the click handler.
{
document.addEventListener('DOMContentLoaded', function() {
const addTaskTrigger = document.getElementsByClassName('addTask-trigger')[0];
const addTaskTarget = document.getElementsByClassName('addTask-target')[0];
const addTaskValue = document.getElementsByClassName('addTask-value')[0];
let nextId = 0;
const todos = [];
const addTask = (task, id, tableItem) => {
let idSpanTd = document.createElement('td');
let taskSpanTd = document.createElement('td');
//要素内のHTML文章を変更する
idSpanTd.innerText = id;
taskSpanTd.innerText = task;
//生成したテーブル要素をブラウザに表示する
tableItem.append(idSpanTd);
tableItem.append(taskSpanTd);
addTaskTarget.append(tableItem);
return(task,id)
};
//Button要素を生成する
const addButton = (tableItem, removeButton, createButton) => {
let createButtonTd = document.createElement('td');
let removeButtonTd = document.createElement('td');
//要素内のHTML文章を変更する
createButton.innerText = '作業中';
removeButton.innerText = '削除';
//生成したテーブル要素をブラウザに表示する
tableItem.append(createButtonTd);
tableItem.append(removeButtonTd);
addTaskTarget.append(tableItem);
//生成したbutton要素を生成する
createButtonTd.append(createButton);
removeButtonTd.append(removeButton);
};
//追加ボタンをクリックした際にタスクを追加する処理を行う
addTaskTrigger.addEventListener('click', () => {
const task = addTaskValue.value;
const tableItem = document.createElement('tr');
const removeButton = document.createElement('button');
const createButton = document.createElement('button');
addTask(task, nextId++, tableItem);
addButton(tableItem, removeButton, createButton);
addTaskValue.value = '';
removeButton.addEventListener('click', delete_element, false);
});
//チェックリスト用オブジェクト
const todo = {
task: 'taskSpanTd',
status: '作業中'
};
todos.push(todo);
// //削除ボタンを押した時にタスクを削除する
function delete_element () {
let tabletag = this.closest ('tr');
if (tabletag)
tabletag.remove ();
}
});
}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel ="stylesheet" href="css/style.css">
<title>Todoリスト</title>
</head>
<body>
<h1>Todoリスト</h1>
<p>
<input type="radio" name="status" value="1" checked="checked">全て
<input type="radio" name="status" value="2">作業中
<input type="radio" name="status" value="3">完了
</p>
<p></p>
<table>
<thead>
<th>ID</th>
<th>コメント</th>
<th>状態</th>
<th></th>
</thead>
<tbody class ="addTask-target"></tbody>
</table>
<h2>新規タスクの追加</h2>
<input class="addTask-value" type="text" />
<button class="addTask-trigger" type="button">追加</button>
<script src="js/main.js"></script>
</body>
</script>
</html>
From the code in my previous question, i now have a function "knapsack" that is supposed to disable the buttons when the total weight(tot_weight) is greater than or equal to the maximum weight("max_weight"). I need it to disable all the "add" buttons when the condition is met.(this will cause no more input to be accepted when max capacity is reached)
My code does not work correctly, it justs disable the last button after only selecting one item (i dont think it checks the condition).
arr_items = new Array();
knap = new Array();
let input = document.getElementById("userinput");
let input2 = document.getElementById("itemName");
let input3 = document.getElementById("itemWeight");
let input4 = document.getElementById("itemValue");
let ul = document.getElementById("list");
let ul2 = document.getElementById("knap")
let listCount = 0;
let myfunction2;
let knapsack;
let max_weight;
myfunction2 = () =>{
input.value = "";
}
let inputLength=() => input2.value.length;
let addValues = () =>{
inputs = {
name : input2.value,
weight : parseFloat(input3.value),
value : parseInt(input4.value)
}
arr_items.push(inputs);
console.log(arr_items);
createListElement();
myfunction2();
}
let createListElement = () => {
var li = document.createElement("li");
li.appendChild(document.createTextNode(input2.value));
ul.appendChild(li);
input2.value = "";
input3.value = "";
input4.value = "";
let btn = document.createElement("button");
btn.appendChild(document.createTextNode("Add"));
li.appendChild(btn);
btn.className = "butt";
btn.id = listCount;
btn.onclick = addTo;
listCount++; // increment the list count variable
console.log(input.value);
max_weight = input.value;
knapsack = (max_weight,knap)=>{
let tot_weight = 0;
for(i=0; i<knap.length;i++){
tot_weight = knap[i].weight + tot_weight;
}
console.log(tot_weight);
console.log(max_weight);
if (tot_weight >= max_weight){
btn.disabled = true;
}
}
}
function addTo(){
var li2 = document.createElement("li");
var id = parseInt(this.id); // retrieve the id of the button
li2.appendChild(document.createTextNode(arr_items[id].name));
ul2.appendChild(li2);
knap.push(arr_items[id]); //use the id of the button to select array to push to knap from the array item
console.log(knap);
knapsack(max_weight,knap);
}
let addListAfterClick = () =>{
if (inputLength() > 0) {
addValues();
}
}
<!DOCTYPE html>
<html>
<head>
<title>KnapSack</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>KnapSack</h1>
<div>
<input id="userinput" type="number" placeholder="Enter Capacity">
</div><br>
<div>
<p>Items Information:</p>
<input id="itemName" type="text" placeholder="enter item name">
<input id="itemWeight" type="number" placeholder="enter item weight(kg)">
<input id="itemValue" type="number" placeholder="enter item value">
<button onclick="addListAfterClick()" id="value">Enter</button>
</div>
<ul id="list">LIST OF 20 ITEMS TO CHOOSE FROM
</ul>
<ul id="knap"> LIST OF ITEMS IN KNAPSACK
</ul>
<div>
<button onclick="myFunction()" id="done">Done</button>
</div>
<p id="demo"></p>
<script type="text/javascript" src="script.js"></script>
<script src="jquery-3.2.1.min.js" ></script>
</body>
</html>
From your code max_weight is being reset every time the "Add" button is clicked, this might make the condition to disable the "Add" buttons behave abnormally.
To disable all the buttons, you have to get all the buttons you created with the ClassName you assigned to them. Here is the modification of your code
arr_items = new Array();
knap = new Array();
let input = document.getElementById("userinput");
let input2 = document.getElementById("itemName");
let input3 = document.getElementById("itemWeight");
let input4 = document.getElementById("itemValue");
let ul = document.getElementById("list");
let ul2 = document.getElementById("knap")
let listCount = 0;
let myfunction2;
let knapsack;
let max_weight;
let tot_weight = 0;
myfunction2 = () =>{
//input.value = ""; I had to comment this line out to avoid resetting max_weight value everytime the add button is click
// since we need to evaluate it everytime
}
let inputLength=() => input2.value.length;
let addValues = () =>{
inputs = {
name : input2.value,
weight : parseFloat(input3.value),
value : parseInt(input4.value)
}
arr_items.push(inputs);
console.log(arr_items);
createListElement();
myfunction2();
}
let createListElement = () => {
var li = document.createElement("li");
li.appendChild(document.createTextNode(input2.value));
ul.appendChild(li);
input2.value = "";
input3.value = "";
input4.value = "";
let btn = document.createElement("button");
btn.appendChild(document.createTextNode("Add"));
li.appendChild(btn);
btn.className = "butt";
btn.id = listCount;
btn.onclick = addTo;
listCount++; // increment the list count variable
console.log(input.value);
max_weight = input.value;
knapsack = (max_weight,knap)=>{
for(i=0; i<knap.length;i++){
tot_weight = knap[i].weight + tot_weight;
}
console.log(tot_weight);
console.log(max_weight);
if (tot_weight >= max_weight){
let buttons = document.getElementsByClassName("butt"); // get all the buttons
for( let button of buttons){
button.disabled = true; // disable all the buttons
}
}
}
}
function addTo(){
var li2 = document.createElement("li");
var id = parseInt(this.id); // retrieve the id of the button
li2.appendChild(document.createTextNode(arr_items[id].name));
ul2.appendChild(li2);
knap.push(arr_items[id]); //use the id of the button to select array to push to knap from the array item
console.log(knap);
knapsack(max_weight,knap);
}
let addListAfterClick = () =>{
if (inputLength() > 0) {
addValues();
}
}
<!DOCTYPE html>
<html>
<head>
<title>KnapSack</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>KnapSack</h1>
<div>
<input id="userinput" type="number" placeholder="Enter Capacity">
</div><br>
<div>
<p>Items Information:</p>
<input id="itemName" type="text" placeholder="enter item name">
<input id="itemWeight" type="number" placeholder="enter item weight(kg)">
<input id="itemValue" type="number" placeholder="enter item value">
<button onclick="addListAfterClick()" id="value">Enter</button>
</div>
<ul id="list">LIST OF 20 ITEMS TO CHOOSE FROM
</ul>
<ul id="knap"> LIST OF ITEMS IN KNAPSACK
</ul>
<div>
<button onclick="myFunction()" id="done">Done</button>
</div>
<p id="demo"></p>
<script type="text/javascript" src="script.js"></script>
<script src="jquery-3.2.1.min.js" ></script>
</body>
</html>
I think this should work as expected
The issue is that in createListElement() you are only disabling the button you just created:
let btn = document.createElement("button");
...
if (tot_weight >= max_weight){
btn.disabled = true;
}
What you want is for all buttons to be disabled, so you could do something like getting all buttons by className, and disabling them in a loop:
allButtons = document.getElementsByClassName( "butt" );
if (tot_weight >= max_weight){
for ( const button of allButtons ) {
button.disabled = true;
}
}
The conditional is definitely being checked every time. This should fix it.