I have an array n i have a four buttons n I just want to display array values ,if i click on first button ,first value should be displayed ,click on second button ,second value should be displayed n so on using addEventListener event handler but there is a problem when i click it directly display last value?
var element = document.querySelectorAll('.box1');
var city = document.querySelector('#name');
for (var i = 0; i < element.length; i++) {
element[i].addEventListener('click', function () {
var i = 0;
var places = ['San diago,USA', 'chicago,USA', 'phoenix,USA', 'New york,USA'];
while (i <places.length) {
console.log(city.innerHTML = places[i]);
i++;
}
});
}
You were iterating over the list of buttons, then inside each handler were also iterating over the full list (using the same variable i). Each button only needs one handler, so you only need one loop.
I moved your "Cities" array outside the function, there's no reason to define it separately inside each handler.
const places = ['San diego,USA', 'chicago,USA', 'phoenix,USA', 'New york,USA'];
let element = document.querySelectorAll('.box1');
let city = document.querySelector('#name');
for (let i = 0; i < element.length; i++) {
element[i].addEventListener('click', function() {
city.innerHTML = places[i];
});
}
<button class="box1">One</button>
<button class="box1">Two</button>
<button class="box1">Three</button>
<button class="box1">Four</button>
<div id="name"></div>
Take special note of the use of let i instead of var i inside that for loop -- ES6 variables are scoped differently; if I had used var there then all four events would get the value of i after the loop has run (so all the buttons would be looking for places[4]!). With let or const the variable is scoped within its block, so the value you want is captured by each iteration in the loop.
Related
I am working on a project where the user decides how many buttons are there, and then each button triggers a different function.
What I have done is: I have an input that asks "Enter the number of buttons" and a "Submit" button. When the "Submit" button is clicked, the value of variable n is set to the user-defined value.
I then have the following code (assuming the user has set n to 10):
for (i = 0; i < 10; i++) {
var x = document.createElement('div');
x.id = i;
x.innerHTML = i;
x.onclick = function() {alert(i)};
document.body.appendChild(x);
}
What I want is, that when div with id i is clicked, the pop-up message says i. But what has ended up happening is, that no matter which div I click, the pop-up message always says 10.
Why is this happening? How to fix this?
The only thing you need to change is the assignment of i inside the for-loop. Use let to define a locally-scoped variable. Also, use textContent instead of innerHTML for simple text. It is recommended to used const/let rather than var.
for (let i = 0; i < 10; i++) {
const x = document.createElement('div');
x.id = i;
x.textContent = i;
x.onclick = function() { alert(i) };
document.body.appendChild(x);
}
By iterating over your NodeList elements, you can take this next approach.
First of all, append all your created divs in your HTML and continue by looping through the elements list by document.querySelectorAll("div")
That way you select all elements and then assign an addEventListener to each one of the items. On your alert function, print this.id and it will return you the number of the id of the element which corresponds to your i index.
It would be the same also if you just put the whole addEventListener function inside the other loop.
I just separated both so you can understand it better.
for (i = 0; i < 10; i++) {
var x = document.createElement('div');
x.id = i;
x.innerHTML = i;
document.body.appendChild(x);
}
let divs = document.querySelectorAll("div");
for(var a= 0; a < divs.length; a++){
divs[a].addEventListener("click", function(){
alert(this.id);
});
}
You can use getAttribute to read the id of the elements. I show you an example:
for (i = 0; i < 10; i++) {
var x = document.createElement('div');
x.id = i;
x.innerHTML = i;
x.onclick = function(e) {
let dataId= e.currentTarget.getAttribute("id")
alert(dataId)
};
document.body.appendChild(x);
}
Explanation:
getAtrribute() returns the value of an html attribute as a string, just enter the name of the attribute in braces to get the value. In this case I entered "id" which is the value we want to retrieve.
Also to get the value of the element where you click I use currentTarget, to accurately retrieve the value of the div that the iteration creates. If you use target, and inside the div you have more elements, this code will generate an error. Therefore, it is important to use currentTarget for this application.
This happen because after the initialisationn the function will look for the value of i which is always 10 (once it has been initialized)
EDIT
As explained by #Mr. Polywhirl in his better answer, you can use let in your for loop to declare your variable locally instead of globally.
To solve your problem you can pass an event to the function (the click event) and the getting your value.
It can be done with either :
The value of the content (as you did with x.innerHTML)
Adding an id to the div and getting this id
Example :
for (i = 0; i < 10; i++) {
var x = document.createElement('div');
x.id = i;
x.innerHTML = i;
x.onclick = function(event) {
alert(event.target.innerHTML) // with the content
alert(event.target.id) // with the id
};
document.body.appendChild(x);
}
I've looked around for awhile and haven't found any solutions. What I'm trying to do is store the variable that contains my option values into an array with an index for each element that is in the variable so I can call it's index.
Here is my code:
var selectArray = ['Package 1', 'Package 2'];
var selectField = document.getElementById('testS');
for(i = 0; i < selectArray.length; i++) {
let arrayList = selectArray[i];
let arrayOption = document.createElement('option');
selectField.appendChild(arrayOption);
arrayOption.value = arrayList; // Value Option in Option
arrayOption.innerHTML = arrayList; // Text in Option
let newArray = [];
newArray.push(arrayOption.value);
// This doesn't work I want each element in the variable to be indexed in the array. so I can do for example newArray[0] which will return Package 1 from the value.
}
<select name="fromList" id="testS"></select>
Reason I'm trying to push the option values from my loop variable into the array is because I want to select each of there index and append to them another array that contains data.
You just need to change where you are declaring the newArray. let creates block level scope, so if you delcare it within a loop, it is scoped to just that one iteration of the loop. You don't want the variable re-declared upon each iteration of the loop because that wipes out the earlier value.
var selectArray = ['Package 1', 'Package 2'];
var selectField = document.getElementById('testS');
// You need to declare variables in the scope that you will want to use them
let newArray = [];
for(i = 0; i < selectArray.length; i++) {
let arrayList = selectArray[i];
let arrayOption = document.createElement('option');
selectField.appendChild(arrayOption);
arrayOption.value = arrayList; // Value Option in Option
arrayOption.innerHTML = arrayList; // Text in Option
newArray.push(arrayOption.value);
}
console.log(newArray);
<select name="fromList" id="testS"></select>
Now, the next question is why do you really need to even do this? The option elements in the select can always be gotten on-demand as an array with this:
var options = Array.prototype.slice.call(document.querySelectorAll("#testS > option"));
Good afternoon.
I am trying to use the selected value in the options box in a for loop.
The theory being that if the user selects 3, for example, Javascript will populate 3 boxes with a fruit from the array.
Can anyone point me in the right direction? I have enclosed Codepen link too.
function changeText(){
var e = document.getElementById('selectbox');
var strUser = e.options[e.selectedIndex].value;
for (var i=0; i<=strUser; i++) {
document.getElementById('boldStuff').innerHTML = randomFruit + strUser;
}
}
http://codepen.io/jameswinfield/pen/aNWRKm
The ID element should be unique to the entire dom. You are using it multiple times for boldStuff. If you would like to be able to grab them like that you should use a class.
Here is a version that should do what you want: http://codepen.io/anon/pen/KzmGLP?editors=0010
Keep in mind that sets the value to every box, even the hidden ones. You will have to get a new random fruit per box or they will all have the same fruit.
I changed all id="boldStuff" to class="boldStuff",
grabbed all boldStuffs
var boldStuffs = document.getElementsByClassName('boldStuff');
and looped over every boldStuff
for (var i = 0; i < boldStuffs.length; i += 1) {
//And set the value of each boldStuff to a new random fruit.
boldStuffs[i].innerHTML = getRandomItem(fruitsArray);
}
The following line also only runs once so no matter how many boxes there are they will all have the same fruit (because randomFruit is never changed)
var randomFruit = fruitsArray[Math.floor(Math.random() * fruitsArray.length)];
You can use a function to grab a random fruit instead, something like this:
function getRandomItem(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
Then use getRandomItem(fruitsArray); to get a random fruit.
I think I can explain this properly. I have a function that I want to call with an onclick event on several divs.
$scope.dataArray = []; //array for holding values from another function
$scope.myFunction = function(id) {
var val1 = id[0];
var val2 = id[1];
}
And I want to assign this function to an onclick on divs that I append to a parent inside this function.
$scope.appendDivs = function (someData) {
var result = someData; // an array
var parentContainer = document.getElementById('parent-container');
for( var i = 0; i < result.length; i++)
{
var div = document.createElement('div');
div.className = "child-element";
parentContainer.appendChild(div);
div.onclick = function() {
$scope.myFunction(result.id); //pass an array of data to myFunction
};
div.innerHTML = result[i].data1 + "<br>" + result[i].data2;
}
The problem lies in when I click the div to activate the onclick call and I debug to see what's going on, $scope.myFunction always gets passed the length of "result" where nothing is defined at. i.e. a length of 3 has elements 0, 1 and 2. myFunction tries to look at results[3]. Is there a way I can have each div know which element to pass to myFunction?
I was able to get around my problem by piggybacking my value onto div.id. I don't need the id of the div for anything, and I was able to get rid of the dataArray as well. So now I can just pass the value I need into myFunction and it's the corresponding value to the div that is clicked. Thanks for your time though guys!
My page allows users to add and remove input boxes to enter search terms.
The function that allows them to add these, returns a value. (a count variable to keep track of the amount as I want to limit the fields to five.)
I call the function on the click of a button here:
<input type="button" value="+" id="add" onclick="count = addField(count);"/>
As you can see the value of count is returned to the script.
The following is the relevant JS for adding the input field. (The add function also contains an inner function for removing an input field)
//Starts at 1, as there is always at least one input box.
var count = 1;
function addField(count) {
//Only add if the limit is not reached:
if (count<=4){
//Increase the count by 1, alert for demo purposes:
count++;
alert(count);
//Create a div to hold the new input and a new button to remove it:
var divv = document.createElement("div");
divv.setAttribute("id", "div"+count);
divv.setAttribute("class", "divvv")
inputContainer.appendChild(divv);
var id = "tag"+count;
var newField = document.createElement("input");
newField.setAttribute('type', 'text');
newField.setAttribute('class', 'field');
newField.setAttribute('id', id);
divv.appendChild(newField);
var deleteCont = document.createElement("div");
var divId = "cont"+count;
deleteCont.setAttribute("id", "cont"+count);
deleteCont.setAttribute("class", "remCont");
divv.appendChild(deleteCont);
var removeId = "remove"+count;
var remove = document.createElement("input");
remove.setAttribute("type", "button");
remove.setAttribute("value", "-");
remove.setAttribute('class', 'remove');
remove.setAttribute('id', removeId);
//This part is the problem, When the remove button is clicked it WILL remove the
//Relevant div, but I can't find a way to reduce the count after this (i.e, allow
//the user to re-add new fields after reaching the 5 limit and removing some.
//Basically it allows the user to add lets say 3 (Total now at 4). If they then
//remove all three it should allow them to add up to 4 again. But it will only
//allow one. Since the count was at 4 even after they removed 3.
remove.onclick = function () {
var element = document.getElementById("inputContainer");
divv.parentNode.removeChild(divv);
//I tried something like:
// count = count - 1;
//But obviously the value that returns from the addField function is the count
//outside this inner function.
};
deleteCont.appendChild(remove);
return count;
}
}
Hopefully you can understand the issue, if not I have made a short video to illustrate it.
Demo: http://tinypic.com/player.php?v=11ad7j9%3E&s=8#.U1g7kvldVvF
Because your addField function has a variable called count, the count variable in the global scope cannot be accessed by saying count. Additionally, when your inner function references count, it will be a stored value in a closure that is not shared across multiple invocations of addField. This is good for removing the correct item but bad for maintaining the count. I recommend this:
<input type="button" value="+" id="add" onclick="addField()"/>
JS
//Starts at 1, as there is always at least one input box.
var count = 1;
var idGen = 1; // Use to ensure input ids are unique
function addField() { // No longer passing count;
var id = idGen++; // Each field gets a different id;
count++; // Count goes up.
...
button.onclick = function() {
...
count--;
}
...
return; // No longer returning count;
}
As long as you don't need ids to be consecutive, separating your ids from your count will make for a design that is easier to write and maintain.