When a user enters a word in a text input, it is displayed on my page. And so the names can accumulate.
At the same time, I want the names to be pushed into an array. Unfortunately, I can't do it:
function getinnerText() {
const arr = []
const newProduct = document.createElement("li");
newProduct.textContent = `${name}`;
document.querySelector(".nameArea").appendChild(newProduct)
arr.push(name)
}
It always creates me my array with only the last value added.
Does anyone have a solution? Thanks a lot =)!
You need to move your array outside of the function. Each time you call the function, you are recreating the array with only one item.
I would separate the model from the view. Each time you add a product to the array, re-render what is in the array.
const
nameInput = document.querySelector('input[name="product"]'),
addButton = document.querySelector('#add'),
nameArea = document.querySelector('.nameArea');
const products = [];
const render = () => {
nameArea.innerHTML = '';
products.forEach(product => {
const newProduct = document.createElement('li');
newProduct.textContent = product;
nameArea.appendChild(newProduct)
});
}
const handleAdd = (e) => {
products.push(nameInput.value);
nameInput.value = '';
render();
};
document.querySelector('#add').addEventListener('click', handleAdd);
<input name="product" />
<button id="add">Add</button>
<ul class="nameArea"></ul>
Everytime you call the getinnerText function, a new arr variable is created.
After the function is executed, the array will not longer available.
The solution is to move the const arr = [] out from the function declaration like such:
const arr = []
function getinnerText() {
const newProduct = document.createElement("li");
newProduct.textContent = `${name}`;
document.querySelector(".nameArea").appendChild(newProduct)
arr.push(name)
}
You can declare const arr = [] outside from the function getinnerText. So you can get every names you have entered. Otherwise you create an new array every function call.
const arr = []
function getinnerText() {
const newProduct = document.createElement("li");
newProduct.textContent = `${name}`;
document.querySelector(".nameArea").appendChild(newProduct)
arr.push(name)
}
Hope solve the issue :)
You can declare your array outside function and then append your value accordingly inside the function.
const arr = [];
function myFunction(){
const newStr = document.createElement("li");
let inputVal = document.getElementById("inputText").value
newStr.innerHTML= inputVal;
document.getElementById("foo").appendChild(newStr);
arr.push(inputVal);
document.getElementById("inputText").value = "";
console.log(arr);
}
#foo {
display:flex;
flex-direction:column;
}
<input id="inputText" type="input" onchange="myFunction()">
<div id="foo"></div>
Related
When creating elements using a loop and adding a class to them, should I first declare the variable outside the loop?
For example:
const mainContainer = document.queryselector('.main-container');
const arr = [1,2,3,4,5];
arr.forEach((num)=> {
const newEl = document.createElement('div');
newEl.innerHtml = num;
mainContainer.appendChild(newEl);
newEl.addEventListener('click',()=> {
window.open('google.com')
})
})
This would open 5 new tabs, but the only way I can access the element is inside the loop, should I delare newEl outside the loop and just change it with let?
Yes, inside the loop you are calling a function. By default, the function has its scope killed as soon as the function exits/pops, which means the variable will be unset when the function exits and you won't be able to access it outside the function (or even loop).
For your code, there were some errors which have been rectified:
const mainContainer = document.queryselector('.main-container');
const mainContainer = document.getElementsByClassName('main-container')[0];
const arr = [1,2,3,4,5];
arr.forEach((num)=> {
const newEl = document.createElement('div');
newEl.innerText = num;
mainContainer.appendChild(newEl);
console.log(mainContainer);
newEl.addEventListener('click',()=> {
window.open('google.com')
})
})
<div class="main-container"></div>
If you want references to the elements you've created, you can do:
const mainContainer = document.querySelector('.main-container');
const newEls = [1,2,3,4,5].map(num=> {
const newEl = document.createElement('div');
newEl.innerHtml = num;
mainContainer.appendChild(newEl);
newEl.addEventListener('click',()=> {
window.open('google.com')
});
return newEl;
})
Context
I have a function that passes out a Map of ints, and an unrelated int. Here's an example that does work:
const myFunction = () => {
let color_map = new Map();
color_map.set(111, 222);
color_map.set(333, 444);
color_map.set(555, 666);
let rando = 777;
return {color_map, rando};
}
const {color_map, rando} = myFunction();
console.log("Results:", color_map, rando)
My Code
My actual code is very similar:
const makeColorMap = (img) => {
let color_map = new Map();
let psize = 0;
// ...
return {color_map, psize};
}
// makeColorMap() is passed in as 'method'
const {color_map, psize} = method(arr);
However, when I run this, both come out as undefined.
Does this have to do with the anonymous function or something? I'm really lost.
Maybe related, but in a previous iteration, the first two elements of the Map were being put into color_map and psize, respectively. What gives?
Your code works, but you are not calling makeColorMap, instead you call some method:
const makeColorMap = (img) => {
let color_map = new Map();
let psize = 0;
// ...
return {
color_map,
psize
};
}
const arr = [];
const method = makeColorMap;
const {color_map, psize} = method(arr);
console.log(color_map, psize);
What you need to do in your app is to make sure that method is indeed a makeColorMap, which is probably not the case in your app
If we see the code, a word is always repeated (name, surname, position, nation).
const nameInput = document.getElementById('name-personalized')
let nameInputValue
const surnameInput = document.getElementById('surname-personalized')
let surnameInputValue
const positionInput = document.getElementById('position-personalized')
let positionInputValue
const nationInput = document.getElementById('nation-personalized')
let nationInputValue
nameInput.addEventListener('input', (event) => {
let value = event.target.value
value = value.trim().toUpperCase()
nameInputValue = value
})
surnameInput.addEventListener('input', (event) => {
let value = event.target.value
value = value.trim().toUpperCase()
surnameInputValue = value
})
positionInput.addEventListener('input', (event) => {
let value = event.target.value
value = value.trim().toUpperCase()
positionInputValue = value
})
nationInput.addEventListener('input', (event) => {
let value = event.target.value
value = value.trim()
nationInputValue = value
})
I want to write just that word, example:
avoidRepeat(name)
And let's say using a for cycle but I don't know how to do that.
Here's one way. Just wrap all the repeated code up in a function and pass the specifics as argument functions. I have removed the globals and replaced them with callback functions.
I'd say this solution is not optimal as it decreases code flexibility for the sake of making the code shorter. Passing two functions to the same function isn't ideal for readability.
You may find libraries like jquery, rxjs or even functional libraries like ramda could help reduce repetition and keep flexibility and readability intact.
<html>
<head><title>whatever</title></head>
<body>
<label for="name-personalized">name-personalized: </label><input type="text" id="name-personalized"><br>
<label for="surname-personalized">surname-personalized: </label><input type="text" id="surname-personalized"><br>
<label for="position-personalized">position-personalized: </label><input type="text" id="position-personalized"><br>
<label for="nation-personalized">nation-personalized: </label><input type="text" id="nation-personalized">
</body>
<script>
function avoidRepeat(name, mapFn, cbFn) {
const el = document.getElementById(name)
el.addEventListener('input', (event) => {
const val = mapFn(event.target.value);
cbFn(val, event.target);
})
}
const fnTrim = s => s.trim()
const fnTrimUpper = s => s.trim().toUpperCase()
const fnLog = (val, el) => console.log('for', el.getAttribute('id'), 'the value is ' + val)
avoidRepeat('name-personalized', fnTrimUpper, fnLog)
avoidRepeat('surname-personalized', fnTrimUpper, fnLog)
avoidRepeat('position-personalized', fnTrimUpper, fnLog)
avoidRepeat('nation-personalized', fnTrim, fnLog)
</script>
</html>
You can store the data in an object via the input's ID and just add an event listener to the inputs. Then accessed in bracket notation. I also removed -personalized from the keys.
This code is all you need for all of those and even future inputs
var values = {};
const inputs = document.querySelectorAll("input");
inputs.forEach(function(el) {
el.addEventListener('input', (event) => {
values[event.target.getAttribute("id").replace("-personalized","")] = event.target.value.trim()
})
});
You can access the data like this
console.log(values["nation"]);
I am facing a problem: I want the array to save the x value each time the button is clicked.
So, the first time the button is clicked, the console is going to print: [48], the next time [48,48] and the third time [48,48,48]
<button id="me">Click me to print form E to Z</button>
<script type="text/javascript">
const insertOptions = x=>{
console.log(x);
}
const circleInsertOptions = () => {
let myArray = [];
let x = 48;
myArray.push(48);
console.log(myArray);
return myArray;
};
document.getElementById('me').addEventListener('click', circleInsertOptions);
</script>
The myArray variable is local to the function. Each time the function is called, it is initialized with a new array.
If you want to define the array once then you need to define it once and not every time the function is called (i.e. outside the function).
You need to initialize the array outside of the function, otherwise every time you call the function, it will be reset to []
<script type="text/javascript">
let myArray = []; // create array here
const insertOptions = x=>{
console.log(x);
}
const circleInsertOptions = () => {
let x = 48;
myArray.push(48);
console.log(myArray);
return myArray;
};
document.getElementById('me').addEventListener('click', circleInsertOptions);
</script>
let myArray = []; // ARRAY STORED ONCE AS GLOBAL.
const insertOptions = x=>{
console.log(x);
};
const circleInsertOptions = () => {
let x = 48;
myArray.push(48);
console.log(myArray);
return myArray;
};
document.getElementById('me').addEventListener('click', circleInsertOptions);
I get data from the database of which I only need two arrays. Using two variables, I get the result I need, but I understand, that this code is not written correctly. Even npm writes that the arrow function should return something, so I added "return false";
let flagUrls = [];
let countryNames = [];
country.map((country, index) => {
flagUrls[index] = country.flagUrls;
countryNames[index] = country.countryNames;
return false;
});
this.setState({ flagUrls, countryNames });
I tried like this:
let flagsAndCountrys = country.map((country, index) =>[country.flagUrls, country.countryNames])
this.setState({
flagsAndCountrys.flagUrls,
flagsAndCountrys.countryNames
});
mapmethod creates a new array with the return value of the provided function on every element in the calling array.
Notice the word return in the above line. You need to return something that will be inserted in the new array.
So, using map you can create a new array, consisting of objects with only the flagUrls and countryNames field like so:
let result = country.map((country, index) => {
return {
flagUrl: country.flagUrls,
countryName: country.countryNames
}
});
If you want maintain two array of flagUrls and countryNames, you should not be using map. It's better to use forEach here, like so:
let flagUrls = [];
let countryNames = [];
country.forEach((country, index) => {
flagUrls.push(country.flagUrls);
countryNames.push(country.countryNames);
});
Using destructuring for this, replace the first parameter passed to the provided function country with the values like: {flagUrls, countryNames}
country.forEach(({flagUrls, countryNames}, index) => {
flagUrls.push(flagUrls);
countryNames.push(countryNames);
});
The proper way to create two arrays would be to call map twice:
const flagUrls = countries.map(country => country.flagUrl);
const countryNames = countries.map(country => country.countryName);
If you want to do it with only a single iteration, then you'll have to use a loop with side effects - similar to the map call you did, but you'd rather use forEach:
let flagUrls = [];
let countryNames = [];
countries.forEach((country, index) => {
flagUrls[index] = country.flagUrl;
countryNames[index] = country.countryName;
});
or just
let flagUrls = [];
let countryNames = [];
for (const country of countries) {
flagUrls.push(country.flagUrl);
countryNames.push(country.countryName);
}