Extract a value from input a store it in array - javascript

I'm trying to take the user input, which is obtained with an event listener, display it on the page, and store the value in an array for further use. However, the array stays empty. Any ideas?
let arr = [];
function display() {
let p = document.querySelector('p');
let btn = document.querySelector('btn');
let input = document.querySelector('input').value;
btn.addEventListener('click', () => {
p.textContent = input;
arr.push(input);
});
}
display();

function display() {
let p = document.querySelector('p');
let arr = [];
let btn = document.querySelector('btn');
btn.addEventListener('click', () => {
let input = document.querySelector('input').value; // <-- move this line here
p.textContent = input;
arr.push(input);
});
}
display()

Your problem is that you're reading input out before the button has an event listener - so the current value (an empty string) will be read. Make sure to declare input inside the event listener:
btn.addEventListener('click', () => {
let input = document.querySelector("input").value;
p.textContent = input;
arr.push(input);
});

I believe the issue is that document.querySelector('btn') is not properly selecting the button because there is no such thing as a btn element. You'll need to change that to document.querySelector('button'). Then, combine that with what the other answers have mentioned -- you also need to capture the input value inside the event handler function.
let arr = [];
function display() {
let p = document.querySelector("p");
let btn = document.querySelector("button");
btn.addEventListener("click", () => {
let input = document.querySelector("input").value;
p.textContent = input;
arr.push(input);
});
}
display();

Related

How do you link local variables to other functions without having to use global variables?

How do I link up the 3 functions below so I can have mathFormula output an answer?
HTML text:
<div id = "rowContainer"></div>
JavaScript text:
function mathFormula(x, y) {
return x * y;
}
const mainDiv = document.getElementById("rowContainer");
function newRow() {
const input1 = document.createElement("input");
mainDiv.appendChild(input1);
const input2 = document.createElement("input");
mainDiv.appendChild(input2);
const result = document.createElement("div");
mainDiv.appendChild(result);
}
mainDiv('keyup', function() {
const a = input1.value;
const b = input2.value;
const sum = mathFormula(a,b);
result.textContent = sum;
})
Functions can see variables in their containing scope, so the keyup listener, if defined inside the newRow function, captures the context of input elements.
The other thing to notice is that the listener is ambiguous unless attached to a specific row (capturing in scope that row's inputs). The snippet below adds an extra div to hold the row, and attaches the listener at the row-div level.
const mainDiv = document.getElementById('maindiv');
function mathFormula(x, y) {
return x * y;
}
function addRow() {
const rowDiv = document.createElement("div");
mainDiv.appendChild(rowDiv);
const input1 = document.createElement("input");
rowDiv.appendChild(input1);
const input2 = document.createElement("input");
rowDiv.appendChild(input2);
const result = document.createElement("div");
rowDiv.appendChild(result);
rowDiv.addEventListener("keyup", event => {
const a = input1.value;
const b = input2.value;
result.textContent = mathFormula(a, b);
})
}
addRow()
addRow()
<div id="maindiv">
</div>
We only need 2 functions in this case.newRow()&mathFormula.
creating 3 inputs instead of one being a div.
appending all inputs inside our rowContainer.all at once, no need to do them separately.
then i am listening to a click on my button which i created inside html.
so,when we click the button.inside there i am calling our mathFormula function & passing the input1 & input2.
let multiply=mathFormula(input1,input2) which sends the these two inputs to mathFormula as object still.those inputs are then assigned to x,y.
then i am saying x = x.value & y =y .value then returns a single value of x*y which gets stored in the multiply variable. because we said.
let multiply=mathFormula(input1,input2) putting that value inside result input.
i hope it helps you.you can ask if you have any doubts
const mainDiv = document.getElementById("rowContainer");
const btn = document.getElementById("btn");
function mathFormula(x, y) {
x=x.value;
y=y.value
return x * y;
}
newRow(); /*-----Calling the newRow() rightAway*/
function newRow() {
const input1 = document.createElement("input");
const input2 = document.createElement("input");
const result = document.createElement("input");
mainDiv.append(input1, input2, result);
btn.addEventListener("click",()=>{
let multiply=mathFormula(input1,input2)
result.value=multiply;
})
}
<div id="rowContainer"></div>
<button id="btn">Click</button>

Removing input from the DOM and local storage with vanilla JavaScript

I'm creating a ToDo app in vanilla JavaScript.
My goal is to be able to remove the input data from local storage when the corresponding "X" button has been clicked.
So far, when you click on an X button, the corresponding input field and checkbox are removed from the DOM with this function I created -
function removeToDoInput(button, input1, input2, input3) {
if (allToDoInputs.length > 2) {
button.addEventListener("click", () => {
toDoInputContainer.removeChild(input1);
toDoInputContainer.removeChild(input2);
toDoInputContainer.removeChild(input3);
for (let toDoInput = 0; toDoInput < allToDoInputs.length; toDoInput++) {
for (let i = 0; i < localStorage.length; i++) {
localStorage.removeItem("ToDo " + toDoInput);
console.log("test");
}
}
})
}
}
This works fine. But like I mentioned I also need to remove the corresponding input data from local storage.
Here is the 'add-to-do' button functionality. You'll notice the removeToDoInput is called which I don't think is good -
function createToDoInput() {
const newToDoInputCheckbox = document.createElement("INPUT");
newToDoInputCheckbox.setAttribute("type", "checkbox");
const newToDoInput = document.createElement("INPUT");
const newXBtn = document.createElement("SPAN");
toDoInputContainer.appendChild(newToDoInputCheckbox);
toDoInputContainer.appendChild(newToDoInput);
toDoInputContainer.appendChild(newXBtn);
newToDoInputCheckbox.classList.add("checkbox");
newToDoInput.classList.add("to-do-input");
newXBtn.classList.add("X");
newXBtn.innerHTML = "X";
newXBtn.addEventListener("click", removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn));
}
And here is the save button functionality -
function saveToDoInputs() {
localStorage.setItem("Title", toDoListTitle.value.trim());
for (let toDoInput = 0; toDoInput < allToDoInputs.length; toDoInput++) {
if (createToDoInput) {
localStorage.setItem("ToDo " + toDoInput, allToDoInputs[toDoInput].value.trim());
}
}
}
Both of these last functions I mentioned are attached to buttons through click event listeners.
How can I delete the input from local storage as well as the DOM?
This is incorrect and will be called immediately you assign the event handler
newXBtn.addEventListener("click", removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn));
you need
newXBtn.addEventListener("click", function() { removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn)});
or similar
I have redesigned your code and now it
wraps the elements in their own container
delegates click and change to the list container
use relative addressing (closest)
gives the todo a unique ID and stores it in an object
retrieves the object from local storage when loading
adds the object to localStorage when changed
I also added a select all and delete selected
NOTE I have commented the localStorage interaction out because stacksnippets do not allow access to localStorage. Just uncomment them on your page
let todos = {};
// const saveTodos = localStorage.getItem("ToDo");
// if (saveTodos) todos = JSON.parse(saveTodos);
const toDoInputContainer = document.getElementById("toDoInputContainer");
const toggleSelDel = () => {
document.getElementById("seldel").classList.toggle("hide",Object.keys(todos).length===0); // show if there are actual entries - we can toggle on existense of checkboxes instead
}
const saveAndToggle = (id,why) => {
// localStorage.setItem("ToDo",JSON.stringify(todos));
console.log(id, why);
toggleSelDel()
};
const saveTodo = (id, text) => {
todos[id] = text;
saveAndToggle(id,"added")
};
const removeTodo = id => {
if (todos[id]) {
delete todos[id];
}
saveAndToggle(id,"deleted"); // toggle anyway
};
function createToDoInput() {
const todoContainer = document.createElement("div");
todoContainer.id = 'todo' + new Date().getTime(); // unique ID
const newToDoInputCheckbox = document.createElement("INPUT");
newToDoInputCheckbox.setAttribute("type", "checkbox");
const newToDoInput = document.createElement("INPUT");
const newXBtn = document.createElement("SPAN");
todoContainer.appendChild(newToDoInputCheckbox);
todoContainer.appendChild(newToDoInput);
todoContainer.appendChild(newXBtn);
newToDoInputCheckbox.classList.add("checkbox");
newToDoInput.classList.add("to-do-input");
newXBtn.classList.add("X");
newXBtn.innerHTML = "X";
toDoInputContainer.appendChild(todoContainer);
}
toDoInputContainer.addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.classList.contains("X")) {
const parent = tgt.closest("div")
removeTodo(parent.id);
parent.remove();
}
});
toDoInputContainer.addEventListener("change", function(e) {
const tgt = e.target;
if (tgt.classList.contains("to-do-input")) {
const id = tgt.closest("div").id;
if (tgt.value === "") removeTodo(id);
else saveTodo(id, tgt.value);
}
});
document.getElementById("add").addEventListener("click", createToDoInput);
toggleSelDel(); // possibly show the select all button
document.getElementById("selAll").addEventListener("click", function() {
const checked = this.checked;
[...toDoInputContainer.querySelectorAll("[type=checkbox]")].forEach(chk => chk.checked = checked)
});
document.getElementById("delAll").addEventListener("click", function() {
[...toDoInputContainer.querySelectorAll("[type=checkbox]:checked")].forEach(chk => {
const parent = chk.closest("div");
removeTodo(parent.id);
parent.remove();
});
});
.hide { display: none; }
<button id="add">Add</button>
<div id="seldel" class="hide"><label>Select all<input type="checkbox" id="selAll"/></label><button type="button" id="delAll">Delete selected</button></div>
<div id="toDoInputContainer"></div>

The values are not replacing with new values

firstly, when I search for any city it shows the weather correctly, but when I try to search for another city/country It shows the details of the same city that I have searched for before. I think there is something wrong with my JavaScript code. I think the new values that I'm fetching from the API are not getting replaced by the old values.
let enterCity = document.querySelector("#enterCity");
let city = document.querySelector(".city");
let country = document.querySelector(".country");
let temp = document.querySelector(".temp");
let text = document.querySelector(".text");
let inputVal = enterCity.value;
// the base url
let url = `http://api.weatherapi.com/v1/current.json?q=${inputVal}&key=cb58be19d0d2****************`;
fetch(url).then((response) => {
return response.json();
}).then((data) => {
let search = document.querySelector(".search");
search.addEventListener("click", () => {
let container = document.querySelector(".container");
card = document.createElement("div");
card.className = "card";
city = document.createElement("h2");
city.className = "city";
***The problems are with the innerText down below ***
city.innerText = data.location.name;
country = document.createElement("h5");
country.className = "country";
country.innerText = data.location.country;
temp = document.createElement("h4");
temp.className = "temp";
temp.innerText = data.current.temp_c;
span1 = document.createElement("span");
span1.id = "deg";
span1.innerText = "°C"
temp.appendChild(span1);
icon = document.createElement("img");
icon.className = "icon";
icon.src = data.current.condition.icon;
text = document.createElement("h3");
text.className = "text";
text.innerText = data.current.condition.text;
card.appendChild(city);
card.appendChild(country);
card.appendChild(temp);
card.appendChild(icon);
card.appendChild(text);
container.appendChild(card);
Here, I have also cleared the input value
that I'm taking from the user
enterCity.value = "";
});
});
let search = document.querySelector(".search");
search.addEventListener("click", () => {
let enterCity = document.querySelector("#enterCity");
let city = document.querySelector(".city");
let country = document.querySelector(".country");
let temp = document.querySelector(".temp");
let text = document.querySelector(".text");
var inputVal = enterCity.value;
// the base url
let url = `http://api.weatherapi.com/v1/current.json?q=${inputVal}&key=cb58be19d0d2********************`;
fetch(url).then((response) => {
return response.json();
}).then((data) => {
//Do the remaining works here
})
});
The actual problem was already assigned the value of document.querySelector("#enterCity"); when the page loads instead of on click. So value of enterCity was not changing when you click the search button.
Note : If the key you given in the question is your personal API key,
then please try to change it in the console, because it is not good
idea to publish it in the outside.
This is happening beacause you haven't added onchange event listener on your input(enter city).if you don't add onchange event this will take only your inital value.
So add a onchange listener then call fetch api inside of it.
Dummy example -
let entercity=document.querySelector("#entercity");
entercity.addEventListener('change',()=>{
let inputVal=entercity.value;
let url = `http://api.weatherapi.com/v1/current.json?q=${inputVal}&key=cb58be19d0d2476da35134140211107`;
fetch(url).then((res)=>console.log(res))
.catch((err)=>console.log(err));
})

How to Remove Particular Element from Array in Javascript with a button

I want to be able to press on my trashcan and be able to delete any todo i want. Right now i can only remove the first index off my todo with with the help off splice. Also when i inspect my array in console i want to be able to use true or false. So when i click on my button my object gets removed from my screen and inside off the array in console it should show that my object indeed have been removed and turns into true instead of false( todoIsRemoved: false). here is a link so you can see all off my code: https://jsfiddle.net/marvstarv/tqdzn8bg/.
this is my class:
let p=0;
let allTheToDos = [];
class Todo{
constructor(toDoItem, removedToDo){
this.Id= p ++;
this.toDoItem = toDoItem;
this.removedToDo = removedToDo;
}
}
this is the function i need help with,
function removeTask (){
let liContainer = document.getElementById ("mySection"); // contains my label(checkmark), Li, and trashcan button.
allTheToDos.splice(Todo,1);
liContainer.innerHTML="";
generateHtml();
console.log(allTheToDos);
}
this function is conected to line 64 off my "main.js": deleteButton.addEventListener('click', () =>{removeTask(allTheToDos[i])});
i appriciate all the help, get back to me if anything was unclear.enter code here
I updated your Js file to:
window.onload = function(){
// without this my site keeps realoding when adding a new item
let firstTask = new Todo ('Bädda sängen',false);
let secondTask = new Todo ('Hänga upp tavlorna',false);
let thirdTask = new Todo ('Kick back & realx',false);
// Adding my premade todo's into my Array that has the variable 'allTheToDos'
allTheToDos.push(firstTask);
allTheToDos.push(secondTask);
allTheToDos.push(thirdTask);
// creating a function so that the user can add a new todo
let addButton = document.getElementById('addBtn');
addButton.addEventListener('click',addNewTask);
generateHtml ();
// let checkedLi = document.getElementById('listItem')
// checkedLi.addEventListener('click',)
console.log(allTheToDos);
}
// my puublic
let p=0;
let allTheToDos = [];
class Todo{
constructor(toDoItem, removedToDo){
this.Id= p ++;
this.toDoItem = toDoItem;
this.removedToDo = removedToDo;
}
}
function generateHtml (){
// Creating an Ul for my items
let section = document.getElementById('mySection');
let myUl = document.createElement('ul');
myUl.className = 'listContainer';
section.appendChild(myUl);
// Creating the loop for my premade todo objects
for(i=0; i<allTheToDos.length; i++){
// Create a div wrapper for my li
let myListWrapperItemContainer = document.createElement('div');
myListWrapperItemContainer.className = "listItemsWrapper";
let id = `to_do_${i}`;
myListWrapperItemContainer.id = id;
// Creating Checked button
let checkedIcon = document.createElement('label');
checkedIcon.className = 'checkedIcon listItemsIcon';
checkedIcon.innerHTML = '<i class="fas fa-check"></i>';
//Creating li
let myLi = document.createElement("li");
myLi.classList = "listItem lineTrough";
myLi.id= "listItem";
// Creating delete button
let deleteButton = document.createElement('button');
deleteButton.id ="deleteButton";
deleteButton.className = 'trashCan listItemsIcon';
deleteButton.innerHTML = '<i class="fas fa-trash-alt"></i>';
// OnClick
deleteButton.addEventListener('click', () => {removeTask(id)});
// Adding everything to my html
myListWrapperItemContainer.appendChild(checkedIcon);
myListWrapperItemContainer.appendChild(myLi);
myListWrapperItemContainer.appendChild(deleteButton);
myLi.innerHTML = allTheToDos[i].toDoItem;
myUl.appendChild(myListWrapperItemContainer);
}
}
function addNewTask (stopRefresh){
stopRefresh.preventDefault();
let liContainer = document.getElementById ("mySection");
let inputValue = document.getElementById('textBox').value;
liContainer.innerHTML="";
if (inputValue == ""){
alert("Type in something");
generateHtml();
}
else{
let newInputValue = new Todo (inputValue);
allTheToDos.push(newInputValue);
generateHtml();
}
}
function removeTask (id){
let element = document.getElementById(id);
let index = allTheToDos.findIndex(e => e.toDoItem === element.textContent);
allTheToDos.splice(index,1);
element.parentNode.removeChild(element);
}

Dynamically create buttons with different event calls

I have a problem in the following JavaScript function.
I am trying to create buttons dynamically based on details from the results variable.
The button are created and an event is attached but it seems each button has the exact same event attached.
I need the address variable to be different for each event attached to a button and for that button then to be added to replace text in my macField variable.
function (results) {
var r;
var x, i;
var btn;
for (i = 0; i < results.length; i++) {
app.display("Paired to" + results[i].name + results[i].address);
x = document.getElementById("message2");
r = results[i].address;
w = document.getElementById('macField').value;
btn = document.createElement('input');
btn.onclick = function () {
document.getElementById('macField').value = r;
};
btn.setAttribute('type', 'button');
btn.setAttribute('name', 'sal' + [i]);
btn.setAttribute('id', 'Button' + [i]);
btn.setAttribute('value', results[i].name);
appendChild(btn);
}
}
function (error) {
app.display(JSON.stringify(error));
}
Use immediate function. Change this part:
btn.onclick = function () {
document.getElementById('macField').value = r;
};
like this:
(function(r){
btn.onclick = function () {
document.getElementById('macField').value = r;
};
})(r);
Have a look: http://jsfiddle.net/uebD8/1/
create your function seperately like below
function macFieldValue(val)
{
document.getElementById('macField').value = val;
}
and set button onclick attribute like this
btn.setAttribute('onclick', 'macFieldValue('+r+')');
Just modifying this part:
btn = document.createElement('input');
btn.onclick = function () {
document.getElementById('macField').value = r;
};
to
btn = document.createElement('input');
btn.setAttribute('some_id', r);
btn.addEventListener('click',
function (e) {
var addr = e.source.some_id;
document.getElementById('macField').value = addr;
}, false);
You are hitting an unfortunate curse of JS. Your code would have worked if it wasn't within a for-loop. In any case, you should be using addEventListener.

Categories