error: deleteItem function is not defined in my script - javascript

I wrote a to do list in javascript but this code dose not work and show a deleteItem() is not defined error. I test it in codepen and it works correctly.
window.onload = function () {
let ourForm = document.getElementById("ourform");
let ourField = document.getElementById("todo");
let ourList = document.getElementById("list");
ourForm.addEventListener("submit", e => {
e.preventDefault();
createItem(ourField.value);
});
function createItem(x) {
let ourHtml = `<li>${x}<button onclick="deleteItem(this)">Delete</button></li>`;
ourList.insertAdjacentHTML("beforeend", ourHtml);
ourField.value = "";
ourField.focus();
}
function deleteItem(elementToDelete) {
elementToDelete.parentElement.remove();
}
}
<h1>NEED-TO-DO APP</h1>
<form id="ourform">
<input id="todo" type="text" autocomplete="off">
<button>Create Item</button>
</form>
<h3>Need To Do</h3>
<ul id="list">
</ul>
whats wrong with my script ..

Try copying the deleteItem function outside window.onload function as the scope is not accessible right now.
window.onload = function () {
let ourForm = document.getElementById("ourform");
let ourField = document.getElementById("todo");
let ourList = document.getElementById("list");
ourForm.addEventListener("submit", e => {
e.preventDefault();
createItem(ourField.value);
});
function createItem(x) {
let ourHtml = `<li>${x}<button onclick="deleteItem(this)">Delete</button></li>`;
ourList.insertAdjacentHTML("beforeend", ourHtml);
ourField.value = "";
ourField.focus();
}
}
function deleteItem(elementToDelete) {
elementToDelete.parentElement.remove();
}

Your code is correct
you can delete this line given under below
window.onload = function () {
then you code will work perfect
thank you

Related

Is it possible to keep cursor in the text area after a click even?

I'm a front-end learner. I created a primitive app that I saw in Duolingo or Memrise. It consists of a text-area and buttons situated below with extra Spanish letters which can be used in necessary. I'm a Spanish learner and need to use the letters to type outside the language apps.
The problem is that when I type in the text and click on the button with a specific extra letter the cursor in the text area disappears. I need to click again in the text area. It's a bit annoying. In Duolingo it stays in the area and the use of mouse is reduced. Does anyone know how to fix it?
<div class="container">
<div class="input-container">
<div class="upper-box">
<textarea name="" id="textarea" rows="3"></textarea>
</div>
<div class="input-keyboard">
<button id="a">á</button>
<button id="e">é</button>
<button id="i">í</button>
<button id="o">ó</button>
<button id="u">ú</button>
<button id="n">ñ</button>
<button id="exclamation">¡</button>
<button id="question">¿</button>
<button id="clear">Clear</button>
<!-- input-keyboard ends below -->
</div>
</div>
</div>
const textarea = document.querySelector("#textarea");
// buttons
const clearBtn = document.querySelector("#clear");
const aBtn = document.querySelector("#a");
const eBtn = document.querySelector("#e");
const iBtn = document.querySelector("#i");
const oBtn = document.querySelector("#o");
const uBtn = document.querySelector("#u");
const nBtn = document.querySelector("#n");
const exlBtn = document.querySelector("#exclamation");
const queBtn = document.querySelector("#question");
aBtn.addEventListener("click", function () {
let inputText = (textarea.value += "á");
});
eBtn.addEventListener("click", function () {
let inputText = (textarea.value += "é");
});
iBtn.addEventListener("click", function () {
let inputText = (textarea.value += "í");
});
oBtn.addEventListener("click", function () {
let inputText = (textarea.value += "ó");
});
uBtn.addEventListener("click", function () {
let inputText = (textarea.value += "ú");
});
nBtn.addEventListener("click", function () {
let inputText = (textarea.value += "ñ");
});
exlBtn.addEventListener("click", function () {
let inputText = (textarea.value += "¡");
});
queBtn.addEventListener("click", function () {
let inputText = (textarea.value += "¿");
});
clearBtn.addEventListener("click", function () {
let inputText = (textarea.value = "");
});
In each button click event, you can set focus the textarea after inserting the respective letter. Check below example (With jQuery):
$(document).on("click", "#a", function () {
var text = $("#textarea").val();
$("#textarea").val(text + 'á');
$("#textarea").focus();
}
Even with Javascript you can have a similar approach.
document.getElementById("textarea").focus();

How to delete a DOM element from an array after you've clicked on it?

I was making a simple to-do list. You submit itens from an input and they go to the To-DO section. When you click over them they go to the 'Done' section. And when you click on them again, they vanish forever. It was all working fine.
But I realized the doneItens array kept growing in length, which I wanted to optimize. So I came up with this line of code
doneItens.splice(i, 1);
which goes inside an onclick event, which you can see in the code inside the deleteDone function.
That gives the error, though,
Error:{
"message": "Uncaught TypeError: doneItens.splice is not a function"
If I put it outside and below the onclick event it also doesn't work. How can I do it?
var input = document.getElementById('play');
var toDo = document.getElementsByTagName('ol')[0];
var done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
const newItem = document.createElement('li');
newItem.setAttribute('class', 'item');
newItem.append(input.value);
toDo.append(newItem);
input.value='';
deleteItem();
}
function deleteItem() {
const toBeDone = document.getElementsByClassName('item');
for(let i = 0; i < toBeDone.length; i++) {
toBeDone[i].onclick = () => {
appendItemDone(toBeDone[i]);
toBeDone[i].style.display = 'none';
deleteDone();
}
}
}
function appendItemDone(item) {
const newDone = document.createElement('li');
newDone.setAttribute('class', 'feito')
newDone.append(item.innerText);
done.append(newDone);
}
function deleteDone() {
const doneItens = document.getElementsByClassName('feito');
console.log('done length', doneItens.length)
for (let i = 0; i < doneItens.length; i++) {
doneItens[i].onclick = () => {
doneItens[i].style.display = 'none';
doneItens.splice(i, 1);
}
}
}
<div id='flex'>
<form class='form' onsubmit='handleSubmit(event)'>
<input placeholder='New item' type='text' id='play'>
<button>Send</button>
</form>
<div id='left'>
<h1 id='todo' >To-do:</h1>
<p class='instruction'><i>(Click over to mark as done)</i></p>
<ol id='here'></ol>
</div>
<div id='right'>
<h1>Done:</h1>
<p class='instruction'><i>(Click over to delete it)</i></p>
<p id='placeholder'></p>
<ol id='done'></ol>
</div>
</div>
With the use of JavaScript DOM API such as Node.removeChild(), Element.remove() and Node.parentNode, your task can be solved with this code:
const input = document.getElementById('play');
const todo = document.getElementById('todo');
const done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
// create new "todo" item
const newTodo = document.createElement('li');
newTodo.textContent = input.value;
todo.append(newTodo);
// clean the input field
input.value = '';
// listen to "click" event on the created item to move it to "done" section
newTodo.addEventListener('click', moveToDone);
}
function moveToDone(event) {
// remove "click"-listener to prevent event listener leaks
event.target.removeEventListener('click', moveToDone);
// move clicked todo-element to "done" section
const newDone = event.target.parentNode.removeChild(event.target);
done.append(newDone);
// listen to "click" event on the moved item to then completely delete it
newDone.addEventListener('click', removeFromDone);
debugElementsLeak();
}
function removeFromDone(event) {
// remove "click"-listener to prevent event listener leaks
event.target.removeEventListener('click', removeFromDone);
// complete remove clicked element from the DOM
event.target.remove();
debugElementsLeak();
}
function debugElementsLeak() {
const todoCount = todo.childElementCount;
const doneCount = done.childElementCount;
console.log({ todoCount, doneCount });
}
<div id="flex">
<form class="form" onsubmit="handleSubmit(event)">
<input placeholder="New item" type="text" id="play">
<button>Add item</button>
</form>
<div id="left">
<h1>To-do:</h1>
<p class="instruction"><em>(Click over to mark as done)</em></p>
<ol id="todo"></ol>
</div>
<div id="right">
<h1>Done:</h1>
<p class="instruction"><em>(Click over to delete it)</em></p>
<p id="placeholder"></p>
<ol id="done"></ol>
</div>
</div>
You'll want to use splice,
and then rather than use hidden, 'refresh' the done element by adding all elements in the spliced array.
I've commented my code where I've made changes and why
var input = document.getElementById('play');
var toDo = document.getElementsByTagName('ol')[0];
var done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
const newItem = document.createElement('li');
newItem.setAttribute('class', 'item');
newItem.append(input.value);
toDo.append(newItem);
input.value='';
deleteItem();
}
function deleteItem() {
const toBeDone = document.getElementsByClassName('item');
for(let i = 0; i < toBeDone.length; i++) {
toBeDone[i].onclick = () => {
appendItemDone(toBeDone[i].cloneNode(true));
toBeDone[i].style.display = 'none';
deleteDone();
}
}
}
function appendItemDone(item) {
const newDone = document.createElement('li');
newDone.setAttribute('class', 'feito')
newDone.append(item.innerText);
done.append(newDone);
}
function deleteDone() {
var doneItens = document.getElementsByClassName('feito');
for (let i = 0; i < doneItens.length; i++) {
doneItens[i].onclick = () => {
var splicedArray = spliceFromArray(doneItens,doneItens[i]);// NEW BIT -CALL NEW SPLICE FUNCTION
done.innerHTML=""; // NEW BIT - SET OVERALL DONE TO BLANK ON DELETE
for(var index in splicedArray){// NEW BIT - fOR EACH RETURNED ELEMENT IN THE SPLICE, ADD IT TO THE OVERALL DONE ELEMENT
done.appendChild(splicedArray[index]);
}
}
}
}
function spliceFromArray(arrayInput,element){// NEW BIT - SPLICE FUNCTION THAT RETURNS SPLICED ARRAY
var array = Array.from(arrayInput);
var index = array.indexOf(element);
if(index!=-1){
if(array.length==1 && index == 0){
array = [];
}
else{
array.splice(index,1);
}
}
return array;
}
<div id='flex'>
<form class='form' onsubmit='handleSubmit(event)'>
<input placeholder='New item' type='text' id='play'>
<button>Send</button>
</form>
<div id='left'>
<h1 id='todo' >To-do:</h1>
<p class='instruction'><i>(Click over to mark as done)</i></p>
<ol id='here'></ol>
</div>
<div id='right'>
<h1>Done:</h1>
<p class='instruction'><i>(Click over to delete it)</i></p>
<p id='placeholder'></p>
<ol id='done'></ol>
</div>
</div>

why check is undefined in my code? 'pure js'

** I want when to click on the active button if the checkbox is checked to add filtered class in HTML element but it doesn't work and give me an undefined error in this line check.parentElement.classList.add("filtered"); **
<ul class="ul-list"></ul>
</section>
</main>
<footer class="footer">
<button class="all footer-btn">All</button>
<button class="active footer-btn">Active</button>
<button class="complete footer-btn">Complete</button>
</footer>
let check = document.querySelectorAll(".complete-txt");
let complete_btn = document.querySelector(".complete");
let active_btn = document.querySelector(".active");
let all_btn = document.querySelector(".all");
let edit_list = document.querySelector(".edit-list");
let main_text = document.querySelector(".main-text");
let list_item = document.querySelector(".list-item");
let footer = document.querySelector(".footer");
const generateTemplate = (todo) => {
const html = `
<li class="list-item">
<input type="checkbox" class="complete-txt" name="" id="check"><span class="main-text">${todo}</span><div class="edit-list"></div><div class="delete-list"></div>
</li>
`;
list.innerHTML += html;
};
// add todos event
addForm.addEventListener("submit", (e) => {
e.preventDefault();
const todo = addForm.add.value.trim();
if (todo.length) {
generateTemplate(todo);
addForm.reset();
}
});
active_btn.addEventListener("click", function () {
let check_id = document.querySelector(".complete-txt");
// check.forEach(function () {
debugger;
if (check.checked !== "true") {
check.parentElement.classList.add("filtered");
console.log("hi");
}
// });
// console.log("hi");
console.log("hi");
// console.log(check.checked.value);
});
if the larger document fixes all other inconcistencies you should be able to change the eventlistener to
active_btn.addEventListener("click", function () {
let check_id = document.querySelector(".complete-txt");
if (check_id.checked !== "true") {
check_id.parentElement.classList.add("filtered");
}
});
BUT!!! this will not "fix" all of your errors, like defining let check before the checkbox is created with generateTemplate

Passing onclick event in template literal

I'm trying to pass url through onclick event, its not working.
there is <body onload="displayBookmarks()"> to initialise displayBookmarks function as soon as the page gets loaded
function deleteBookmark(url){
alert(url);
};
function displayBookmarks(){
bookmarksResults.innerHTML = "";
for (let a in bookmarks){
let name = bookmarks[a].name;
let url = bookmarks[a].url;
bookmarksResults.innerHTML += `<div class="well"> <h3> ${name} <a class="btn btn-default" target="_blank" href=${url} >Visit</a> <a onclick=${deleteBookmark(url)} class="btn btn-danger" >Delete</a></h3></div>`
}
}
The main problem is onclick=${deleteBookmark(url)}
As soon as the page loads it starts displaying the url but I want to to be shown only when delete button is pressed.
I've found that there is another way to do this with encapsulation. I don't know if I would recommend doing it like this at all but since you've asked the question.
const app = document.getElementById("app");
const button = ((app) => {
let _url;
const _log = (data) => {
console.log(data);
}
let _content = `<button onclick="(${_log})('${_url}')">test</button>`;
const _setContent = () => {
_content = `<button onclick="(${_log})('${_url}')">test</button>`;
}
const _setUrl = (url) => {
_url = url;
}
return {
setUrl: (url) => {
_setUrl(url);
_setContent();
},
render: () => {
app.innerHTML = _content;
}
}
})(app)
const url = 'www.something.com';
button.setUrl(url);
button.render();
<section id="app">...</section>
const markUp = `
<button onclick="myFunction()">Click me</button>
`;
document.body.innerHTML = markUp;
window.myFunction = () => {
console.log('Button clicked');
};

Best way to store Local Storage?

I've made a start to a to do list. I've got it adding an item when you submit an item.
I want to now add local storage when you refresh the page so the items are saved in the browser.
I obviously need to save all the times when the page is refreshed but because my items only update on click I'm not sure how to grab that function data outside the function and save the items.
Any ideas?
Cheers
JS Fiddle:
https://jsfiddle.net/x1bj8mfp/
// When submit item
var submit = document.getElementById('form');
submit.addEventListener('submit', addItem);
var items = [];
var itemValues = document.getElementById('items');
var listContainer = document.createElement('ul');
itemValues.appendChild(listContainer);
// Add item
function addItem(e) {
e.preventDefault();
var item = this.querySelector('[name=item]');
var itemValue = item.value;
items.push(itemValue);
item.value = '';
// Output items
var listItems = document.createElement('li');
listItems.innerHTML = itemValue;
listContainer.appendChild(listItems);
}
You could write the whole array to local storage whenever you add an item:
localStorage.setItem('items', JSON.stringify(items));
Then on page load you would read from local storage the array and assign it back to your variable, or set it to [] (like now), if nothing is in local storage, and then display these items:
var items = JSON.parse(localStorage.getItem('items')) || [];
items.forEach(function (itemValue) {
var listItems = document.createElement('li');
listItems.textContent = itemValue;
listContainer.appendChild(listItems);
});
This updated JSFiddle has that code included.
Of course, you will need some function to delete items as well, otherwise you can only grow your list.
Here's a full solution for you. Note that the code snippet won't work here, due to the cors and sandbox. Just paste it into your code editor.
var submit = document.getElementById('form');
submit.addEventListener('submit', addItem);
var items = [];
var itemValues = document.getElementById('items');
var listContainer = document.createElement('ul');
itemValues.appendChild(listContainer);
//retrieve data after reload
window.onload = function() {
if (localStorage.userData != undefined) {
var userData = JSON.parse(localStorage.getItem('userData'));
for (var i = 0; i < userData.length; i++) {
var listItems = document.createElement('li');
listItems.innerHTML = userData[i];
listContainer.appendChild(listItems);
items = userData;
}
}
}
// Add item
function addItem(e) {
e.preventDefault();
var item = this.querySelector('[name=item]');
var itemValue = item.value;
items.push(itemValue);
item.value = '';
// Output items
var listItems = document.createElement('li');
listItems.innerHTML = itemValue;
listContainer.appendChild(listItems);
localStorage.setItem('userData', JSON.stringify(items));
}
<main>
<form id="form">
<input class="form-input" type="text" name="item" placeholder="Add item">
<input class="btn btn-block" type="submit" value="Submit">
</form>
<div id="items"></div>
<div id="completed"></div>
</main>
Here some helpful small example for local storage
function save() {
var fieldvalue = document.getElementById('save').value;
localStorage.setItem('text', fieldvalue);
}
function load() {
var storedvalue = localStorage.getItem('textfield');
if (storedvalue) {
document.getElementById('textfield').value = storedvalue;
}
}
function remove() {
document.getElementById('textfield').value = '';
localStorage.removeItem('textarea');
}
<body onload="load()">
<input type="textarea" id="textfield">
<input type="button" value="Save" id="save" onclick="save()">
<input type="button" value="remove" id="remove" onclick="clr()">
</body>
<!--save& run this in local to see local storage-->

Categories

Resources