Why I cannot add new note after editing created one? - javascript

I cannot add new Note after editing. How can I exit from the cycle?
This is a part where I create a new note
const createNote = () => {
if (button.className === "button") {
const div = document.createElement("div");
div.setAttribute("class", "note");
div.textContent = input.value;
field.appendChild(div);
const btn = document.createElement("button");
btn.setAttribute("class", "edit");
btn.textContent = "Edit";
div.appendChild(btn);
const del = document.createElement("button");
del.setAttribute("class", "del");
del.textContent = "Delete";
div.appendChild(del);
console.log("Note has been created");
input.value = "";
}
Here is a part where I want to edit created Note but also I want to create a new one (this part is inside function createNote)
const edit = document.querySelectorAll(".edit");
for (let i of edit) {
i.onclick = () => {
input.value = i.previousSibling.nodeValue;
button.innerText = "Edit";
button.classList.add("editable");
/*button.classList.remove("button");*/
if (button.className === "button editable") {
button.onclick = () => {
i.previousSibling.nodeValue = input.value;
input.value = "";
button.classList.remove("editable");
button.classList.add("button");
button.innerText = "Add";
};
}
};
}
};
button.onclick = createNote;
Here is HTML that I am using
<body>
<div class="container">
<div class="insert">
<input type="text" name="Note" id="noteId" placeholder="add note">
<button class="button">Add</button>
</div>
<div class="field">
<div class="note">Test note
<button class="edit">Edit</button>
<button class="del">Delete</button>
</div>
</div>
</div>
<script src="js/index.js"></script>
</body>

Related

How can I make my delete function work in my todo app?

I am making a todo app. In the app, there are delete and edit functions. But the Delete function works at the first todo. If I try other todos, It deletes a lot of todos. I tried many ways but disn't work. Please help!
const todoForm = document.querySelector(".todo-form");
const todos = document.querySelector(".todos");
const todoTitle = document.querySelector(".todo-title");
const modal = document.querySelector("#modal");
const modalClose = document.querySelector(".close-button");
const editedText = document.querySelector(".edited-text ");
const submitEdit = document.querySelector(".submit");
const todoList = [];
let totalTodo = 0;
function findFromArray(id, array) {
for (let i = 0; i < array.length; i++) {
if (id === array[i].id) {
return array[i];
}
}
return null;
}
function deleteTodo(id) {
const element = document.getElementById(id);
element.remove();
const data = findFromArray(id, todoList);
todoList.splice(todoList.indexOf(data), 1);
}
function editTodo(id) {
const element = document.querySelector("#" + id + " h1");
modal.showModal();
modalClose.addEventListener("click", () => {
modal.close();
});
submitEdit.addEventListener("click", () => {
const newTodoText = editedText.value;
element.innerText = newTodoText;
modal.close();
});
}
todoForm.addEventListener("submit", (e) => {
e.preventDefault();
let title = todoTitle.value;
const newTodo = document.createElement("div");
const h1 = document.createElement("h1");
const deleteButton = document.createElement("button");
const editButton = document.createElement("button");
deleteButton.innerText = "Delete";
editButton.innerText = "Edit";
todoList.push({
id: "Todo" + totalTodo,
title,
});
totalTodo++;
for (let i = 0; i < todoList.length; i++) {
newTodo.classList.add("todo-card");
todos.appendChild(newTodo);
h1.innerText = todoList[i].title;
deleteButton.addEventListener("click", () => deleteTodo(todoList[i].id));
editButton.addEventListener("click", () => editTodo(todoList[i].id));
newTodo.appendChild(h1);
newTodo.appendChild(deleteButton);
newTodo.appendChild(editButton);
newTodo.id = todoList[i].id;
}
todoTitle.value = "";
});
<body>
<h1 class="todo-heading">Todo App</h1>
<form class="todo-form">
<input class="todo-title" type="text" placeholder="Todo Name" />
<input type="Submit" class="todo-button" />
</form>
<br />
<div class="todos"></div>
<dialog id="modal">
<h1>Edit</h1>
<input type="text" class="edited-text" placeholder="New Todo" />
<br />
<br />
<button class="submit">Submit</button>
<button class="close-button">
<svg class="svg-icon" viewBox="0 0 20 20">
<path
d="M10.185,1.417c-4.741,0-8.583,3.842-8.583,8.583c0,4.74,3.842,8.582,8.583,8.582S18.768,14.74,18.768,10C18.768,5.259,14.926,1.417,10.185,1.417 M10.185,17.68c-4.235,0-7.679-3.445-7.679-7.68c0-4.235,3.444-7.679,7.679-7.679S17.864,5.765,17.864,10C17.864,14.234,14.42,17.68,10.185,17.68 M10.824,10l2.842-2.844c0.178-0.176,0.178-0.46,0-0.637c-0.177-0.178-0.461-0.178-0.637,0l-2.844,2.841L7.341,6.52c-0.176-0.178-0.46-0.178-0.637,0c-0.178,0.176-0.178,0.461,0,0.637L9.546,10l-2.841,2.844c-0.178,0.176-0.178,0.461,0,0.637c0.178,0.178,0.459,0.178,0.637,0l2.844-2.841l2.844,2.841c0.178,0.178,0.459,0.178,0.637,0c0.178-0.176,0.178-0.461,0-0.637L10.824,10z"
></path>
</svg>
</button>
</dialog>
I was expecting to remove a todo element and the todo data. But It removes a lot of todo elements and data. I tried the splice method and the delete keyword but didn't work. Please help!
I think the problem is with the for loop you are using to create the new elements. The loop is iterating through the entire todoList array, but it should only be creating a new todo element for the last array item.
todoForm.addEventListener("submit", (e) => {
e.preventDefault();
let title = todoTitle.value;
const newTodo = document.createElement("div");
const h1 = document.createElement("h1");
const deleteButton = document.createElement("button");
const editButton = document.createElement("button");
deleteButton.innerText = "Delete";
editButton.innerText = "Edit";
todoList.push({
id: "Todo" + totalTodo,
title,
});
totalTodo++;
const lastTodo = todoList[todoList.length - 1];
newTodo.classList.add("todo-card");
todos.appendChild(newTodo);
h1.innerText = lastTodo.title;
deleteButton.addEventListener("click", () => deleteTodo(lastTodo.id));
editButton.addEventListener("click", () => editTodo(lastTodo.id));
newTodo.appendChild(h1);
newTodo.appendChild(deleteButton);
newTodo.appendChild(editButton);
newTodo.id = lastTodo.id;
todoTitle.value = "";
});
Also, like Jelmer commented.. In the deleteTodo function, remove todoList =. You should use the splice method directly on the todoList array to remove the element.
todoList.splice(todoList.indexOf(data), 1);

Add span text to input text value on click

I am looking for a way to add text from my span tag into the input value field when you click on a checkbox.
I do not want to use jQuery for this, only JavaScript.
I have done it so it adds the text into the input field but when you actually click on the input it doesn't recognise that my text is there. Does anyone know how I go about this so it recognises I have added text to the input field? Any help would be appreciated.
Code here:
const inputContainer = document.querySelector('.input-container');
const spanText = document.querySelector('.span-t');
const checkbox = document.querySelector('#checkbox');
const check = document.getElementById('check');
const btn = document.querySelector('.btn');
/* Add Input Field */
const applyInput = function(){
const inputDiv = document.createElement("div");
const inputContent = `<div class="input-container">
<div>
<input class="input" type="text" name="input-code" value=""></input>
</div>
<button type="submit" class="btn" disabled="">
<span>Submit</span>
</button>
</div>`;
inputDiv.id = "input-container";
inputDiv.innerHTML = inputContent;
};
applyInput();
/* Add Span Text */
const span = document.createElement('div');
if(document.getElementById('p-text') !== null) document.getElementById('p-text').parentNode.removeChild(document.getElementById('p-text'));
span.id = "p-text";
span.innerHTML += '<p class="p-text">P Text<span class="span-t">Span Text</span></p>';
inputContainer.after(span);
/* Add Checkbox */
const addingCheckbox = () => {
if(document.getElementById('checkbox') !== null) document.getElementById('checkbox').parentNode.removeChild(document.getElementById('checkbox'));
const addCheckboxHtml = document.createElement('div');
addCheckboxHtml.id = 'checkbox';
addCheckboxHtml.className = 'checkboxEl';
addCheckboxHtml.innerHTML = `<label class="checkbox"><input type="checkbox" id="check"><span></span></label>`;
if(document.getElementById('checkbox') === null) {
spanText.after(addCheckboxHtml);
}
};
addingCheckbox();
/* Add if Checked */
checkbox.addEventListener('click', () => {
document.querySelector('.input').value = spanText.innerHTML;
});
check.onchange = function() {
btn.disabled = !this.checked;
};
SIMPLIFIED CHECK
You can see that this behavior is totally possible - the little snippet below shows a simplified case.
const span = document.querySelector("#from")
const input = document.querySelector("#to")
const cb = document.querySelector("#cb")
const btReset = document.querySelector("#reset")
const btLog = document.querySelector("#log")
cb.addEventListener("change", function(e) {
input.value = span.innerHTML
})
btReset.addEventListener("click", function() {
cb.checked = false
input.value = ''
})
btLog.addEventListener("click", function() {
console.log("input value:", input.value)
})
.container {
margin-bottom: 16px;
}
<div class="container">
<span id="from">This is the text.</span>
</div>
<div class="container">
<input type="text" id="to" /><input type="checkbox" id="cb" />
</div>
<div class="container">
<button id="reset">RESET</button><button id="log">LOG INPUT VALUE</button>
</div>
CODE UPDATE
Now the snippet you gave works without an error.
/* Add Input Field */
const applyInput = function() {
const inputDiv = document.createElement("div");
const inputContent = `
<div class="input-container">
<div>
<input class="input" type="text" name="input-code" value="" />
</div>
<button type="submit" class="btn" disabled="">
<span>Submit</span>
</button>
</div>
`;
inputDiv.id = "input-container";
inputDiv.innerHTML = inputContent;
// you need to add the created element to the DOM,
// e.g. append it to the body
document.body.append(inputDiv)
};
applyInput();
// only elements that are created can be queried, so
// these variables must be initialized AFTER the element(s)
// they are supposed to get exist in the document (DOM)
const inputContainer = document.querySelector('.input-container');
const btn = document.querySelector('.btn');
/* Add Span Text */
// the creation of the span has to be also encapsulated in
// a function - this way it's easier to handle
const addingSpan = () => {
const span = document.createElement('div');
if (document.getElementById('p-text') !== null) document.getElementById('p-text').parentNode.removeChild(document.getElementById('p-text'));
span.id = "p-text";
span.innerHTML += '<p class="p-text">P Text<span class="span-t">Span Text</span></p>';
inputContainer.after(span);
}
addingSpan()
// element after it is actually created
const spanText = document.querySelector('.span-t');
/* Add Checkbox */
const addingCheckbox = () => {
if (document.getElementById('checkbox') !== null) document.getElementById('checkbox').parentNode.removeChild(document.getElementById('checkbox'));
const addCheckboxHtml = document.createElement('div');
addCheckboxHtml.id = 'checkbox';
addCheckboxHtml.className = 'checkboxEl';
addCheckboxHtml.innerHTML = `<label class="checkbox"><input type="checkbox" id="check"><span></span></label>`;
if (document.getElementById('checkbox') === null) {
spanText.after(addCheckboxHtml);
}
};
addingCheckbox();
// element after it is actually created
const checkbox = document.querySelector('#checkbox');
const check = document.getElementById('check');
/* Add if Checked */
checkbox.addEventListener('click', () => {
document.querySelector('.input').value = spanText.innerHTML;
});
check.onchange = function() {
btn.disabled = !this.checked;
};
UPGRADED CODE
I think the following snippet does what your original code does, but the structure is cleaner, simpler.
const getInputHtml = () => `
<div class="input-container">
<div>
<input class="input" type="text" name="input-code" value=""></input>
</div>
<button type="submit" class="btn" disabled="">
<span>Submit</span>
</button>
</div>
`;
const getSpanHtml = () => `<p class="p-text">P Text<span class="span-t">Span Text</span></p>`;
const getCheckboxHtml = () => `<label class="checkbox-label"><input class="checkbox" type="checkbox" id="check" /></label>`;
// only execute function, if selector cannot be found in DOM
const ifNotExistsInDomFn = (selector) => (fn) => {
if (!document.querySelector(selector)) {
return fn()
}
}
const appendHtmlStrTo = (el) => (str) => {
el.insertAdjacentHTML('beforeend', str)
};
const appendHtmlStrToBody = appendHtmlStrTo(document.body);
// IIFE: Immediately Invoked Function Expression
(function() {
// creating UI
const inputHtml = getInputHtml()
appendHtmlStrToBody(inputHtml)
const spanHtml = getSpanHtml()
ifNotExistsInDomFn(".p-text")(() => appendHtmlStrToBody(spanHtml))
const checkboxHtml = getCheckboxHtml()
ifNotExistsInDomFn(".checkbox")(() => appendHtmlStrToBody(checkboxHtml))
// setting event handlers
const cb = document.querySelector(".checkbox")
cb.addEventListener("click", function() {
document.querySelector(".input").value = document.querySelector(".span-t").innerHTML
})
cb.addEventListener("change", function() {
document.querySelector(".btn").disabled = !cb.checked
})
})();

JavaScript - Comments duplicating on another div

I am creating a comment box and I managed to append whatever I type to a div I wanted, however I have added another input and trying to append that along with the comments, however when I do this the second time,it appends both the previous and current comment therefore the previous comment duplicates. I know I'm doing something wrong in my display_commnents function, however I'm not entirely sure what it could be, basically I just want whatever is entered on both title and comments to append on the comment-box with title on top and comment just below. Below is my code:
<div class="container">
<h1>Write New Post</h1>
<form>
<input id="title" type="text" placeholder="Title" value="">
<textarea id="" placeholder="Leave us a comment" value=""></textarea>
<input id="giphy" type="text">
<div class="btn">
<input id="submit" type="submit" value="comment">
<button id="clear">Cancel</button>
</div>
</form>
</div>
<div class="comments">
<h2>Comments</h2>
<div id="comment-box" value="submit">
</div>
</div>
And this is my JS code:
const title = document.querySelector('#title')
const field = document.querySelector('textarea');
const textBackUp = title.getAttribute('placeholder')
const backUp = field.getAttribute('placeholder')
const btn = document.querySelector('.btn');
const clear = document.getElementById('clear')
const submit = document.querySelector('#submit')
// const comments = document.querySelector('#comment-box')
const titleText = document.getElementById('title')
const comments = document.getElementById('comment-box')
let title_arr = [];
let comments_arr = [];
title.onfocus = function(){
this.setAttribute('placeholder', '')
}
title.onblur = function(){
this.setAttribute('placeholder', textBackUp)
}
field.onfocus = function(){
this.setAttribute('placeholder','')
this.style.borderColor = '#333'
btn.style.display = 'block'
} // when clicking on this, placeholder changes into ' ', border colour changes and buttons will appear.
field.onblur = function(){
this.setAttribute('placeholder',backUp)
} //click away, placeholder returns
const display_comments = () => {
let list = '<ul>'
title_arr.forEach(title => {
comments_arr.forEach(comment => {
list += `<li>${title} <br>${comment}`
})
})
list += '</ul>'
comments.innerHTML = list
}
clear.onclick = function(e){
e.preventDefault();
btn.style.display = 'none'
title.value = ''
field.value = ''
display_comments()
}
submit.onclick = function(e){
e.preventDefault();
const head = title.value;
const content = field.value;
if(head.length > 0){
title_arr.push(head)
display_comments();
title.value = '';
}
if(content.length > 0){
comments_arr.push(content)
display_comments();
field.value = '';
}
}
any help would be appreciated
The problem is that you have a double nested loop, producing a Cartesion product of the all the introduced titles and the comments.
To solve this, use only one array for collecting the input, so that title and comment are always kept together in one array entry. Such an entry can be an object with two properties, one for the title, and one for the comment.
Here is your code adapted, just for fixing that issue:
const title = document.querySelector('#title')
const field = document.querySelector('textarea');
const textBackUp = title.getAttribute('placeholder')
const backUp = field.getAttribute('placeholder')
const btn = document.querySelector('.btn');
const clear = document.getElementById('clear')
const submit = document.querySelector('#submit')
// const comments = document.querySelector('#comment-box')
const titleText = document.getElementById('title')
const comments = document.getElementById('comment-box')
let arr = []; // Only one array
title.onfocus = function(){
this.setAttribute('placeholder', '');
}
title.onblur = function(){
this.setAttribute('placeholder', textBackUp);
}
field.onfocus = function(){
this.setAttribute('placeholder','');
this.style.borderColor = '#333';
btn.style.display = 'block';
}
field.onblur = function(){
this.setAttribute('placeholder', backUp);
}
const display_comments = () => {
let list = '<ul>';
// Only one loop -- over objects with two properties
arr.forEach(({head, content}) => {
list += `<li><b>${head}</b><br>${content}`;
})
list += '</ul>';
comments.innerHTML = list;
}
clear.onclick = function(e){
e.preventDefault();
btn.style.display = 'none';
title.value = '';
field.value = '';
display_comments();
}
submit.onclick = function(e){
e.preventDefault();
const head = title.value;
const content = field.value;
// Only one if-block
if(head.length > 0 || content.length > 0){
arr.push({head, content}); // Only one push -- of an object
display_comments();
title.value = '';
field.value = '';
}
}
<div class="container">
<h1>Write New Post</h1>
<form>
<input id="title" type="text" placeholder="Title" value="">
<textarea id="" placeholder="Leave us a comment" value=""></textarea>
<div class="btn">
<input id="submit" type="submit" value="comment">
<button id="clear">Cancel</button>
</div>
</form>
</div>
<div class="comments">
<h2>Comments</h2>
<div id="comment-box" value="submit">
</div>
</div>

How to delete a single item when button has clicked in Javascript?

I'm working on a to-do list project and stuck at this part where when a trash button is clicked all the list items will be deleted and it won't add any new to-do items.
I've checked other posts but couldn't really find the answer for my project, please help!
let input = document.querySelector('#todo')
let btn = document.querySelector('#btn');
let list = document.querySelector('#list');
btn.addEventListener('click', () => {
let txt = input.value;
if (txt === "") {
alert('Please write something to do!');
} else {
let li = document.createElement('li');
li.innerHTML = txt;
list.insertBefore(li, list.childNodes[0]);
input.value = '';
const delBtn = document.createElement("i");
delBtn.classList.add("fas", "fa-trash-alt");
li.appendChild(delBtn);
delBtn.addEventListener('click', e => {
list.parentNode.removeChild(list);
})
}
})
list.addEventListener('click', e => {
if(e.target.tagName == 'LI') {
e.target.classList.toggle('checked');
}
})
<div class="todoList">
<h1>To-do List</h1>
<div class="add-element">
<input type="text" id="todo" placeholder="Add new to-do">
<button id="btn">Add</button>
</div>
<div class="element-list">
<ul id="list"></ul>
</div>
</div>
list.parentNode.removeChild(list); deletes all the list, if you want to delete only one element from the list, add a button to every li and change this line to li.parentNode.removeChild(li); like this:
let input = document.querySelector('#todo')
let btn = document.querySelector('#btn');
let list = document.querySelector('#list');
btn.addEventListener('click', () => {
let txt = input.value;
if (txt === "") {
alert('Please write something to do!');
} else {
let li = document.createElement('li');
li.innerHTML = txt;
list.insertBefore(li, list.childNodes[0]);
input.value = '';
const delBtn = document.createElement("i");
li.appendChild(delBtn);
delBtn.addEventListener('click', e => {
li.parentNode.removeChild(li);
})
}
})
list.addEventListener('click', e => {
if(e.target.tagName == 'LI') {
e.target.classList.toggle('checked');
}
})
<div class="todoList">
<h1>To-do List</h1>
<div class="add-element">
<input type="text" id="todo" placeholder="Add new to-do">
<button id="btn">Add</button>
</div>
<div class="element-list">
<ul id="list"></ul>
</div>
</div>

Moving items to different lists with DOM Manipulation JS

I'm creating something like GMAIL functionality with JavaScript ES5 ( I use only const and let, that's it, rest ES5).
So I manage to create the list functionality, all works except that when I select the items and move them to a different list, they lose any functionality, and I can't do anything with them.
I believe I need to use querySelectorAll to get all the lists, but that doesn't work. Not sure what should I do here.
I think I need to select all the lists, and then loop them to add interactivity.
CodePen: https://codepen.io/Aurelian/pen/dJryrX?editors=1010
JS:
window.onload = function() {
//////////////////////////////////
// VARIABLES
//////////////////////////////////
// Form
const form = document.querySelector('#registrar');
const input = form.querySelector('input');
// Lists
const partyList = document.querySelector('.party-lists');
const partyInvitedList = document.querySelector('#list-invited')
const partyGoingList = document.querySelector('#list-going');
const partyNotSure = document.querySelector('#list-not-sure');
const partyNotGoing = document.querySelector('#list-not-going');
// List Options
const listOptions = document.querySelector('.list-options');
const btnMoveToGoing = document.querySelector('.btnMoveGoing');
const btnMoveToNotSure = document.querySelector('.btnMoveNotSure');
const btnMoveToNotGoing = document.querySelector('.btnMoveNotGoing');
const btnDeleteSelected = document.querySelector('.btnDeleteSelected');
//////////////////////////////////
// FUNCTIONS
//////////////////////////////////
function createLI(text) {
const li = document.createElement('li');
const span = document.createElement('span');
span.textContent = text;
li.appendChild(span);
const label = document.createElement('label');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
label.appendChild(checkbox);
li.appendChild(label);
const editButton = document.createElement('button');
editButton.textContent = 'edit';
li.appendChild(editButton);
const removeButton = document.createElement('button');
removeButton.textContent = 'remove';
li.appendChild(removeButton);
return li;
}
//////////////////////////////////
// EVENT HANDLERS
//////////////////////////////////
form.addEventListener('submit', function(e) {
e.preventDefault();
const text = input.value;
input.value = '';
const li = createLI(text);
partyInvitedList.appendChild(li);
});
partyList.addEventListener('click', function(e) {
if (e.target.tagName === 'BUTTON') {
const button = e.target;
const li = button.parentNode;
const ul = li.parentNode;
if (button.textContent === 'remove') {
ul.removeChild(li);
} else if (button.textContent === 'edit') {
const span = li.firstElementChild;
const input = document.createElement('input');
input.type = 'text';
input.value = span.textContent;
li.insertBefore(input, span);
li.removeChild(span);
button.textContent = 'save';
} else if (button.textContent === 'save') {
const input = li.firstElementChild;
const span = document.createElement('span');
span.textContent = input.value;
li.insertBefore(span, input);
li.removeChild(input);
button.textContent = 'edit';
}
}
});
listOptions.addEventListener('click', function(e) {
partyList.querySelectorAll('*:checked').forEach(function (listItems) {
const button = e.target;
var items = listItems.parentNode.parentNode;
if(button.className === 'btnMoveGoing') {
partyGoingList.appendChild(items);
items.checked = false;
var item = listItems;
item.checked = false;
} else if(button.className === 'btnMoveNotSure'){
partyNotSure.appendChild(items);
var item = listItems;
item.checked = false;
} else if(button.className === 'btnMoveNotGoing'){
partyNotGoing.appendChild(items);
var item = listItems;
item.checked = false;
} else if(button.className === 'btnDeleteSelected'){
listItems.parentNode.parentNode.remove();
var item = listItems;
item.checked = false;
}
});
});
}
HTML:
<div class="top">
<form id="registrar">
<input type="text" name="name" placeholder="Invite Someone">
<button type="submit" name="submit" value="submit">Submit</button>
</form>
<div class="list-options">
<button class="btnMoveGoing">Move to Going</button>
<button class="btnMoveNotSure">Move to Not Sure</button>
<button class="btnMoveNotGoing">Move to Not Going</button>
<button class="btnDeleteSelected">Delete Selected</button>
</div>
</div><!-- /top -->
<div class="col">
<h3>Invited</h3>
<ul id="list-invited" class="party-lists">
</ul>
</div>
<div class="col">
<h3>Going</h3>
<ul id="list-going" class="party-lists">
</ul>
</div>
<div class="col">
<h3>Not Sure</h3>
<ul id="list-not-sure" class="party-lists">
</ul>
</div>
<div class="col">
<h3>Not Going</h3>
<ul id="list-not-going" class="party-lists">
</ul>
</div>

Categories

Resources