Function is not behaving as intended. Why? - javascript

Sorry for not being more precise on the title.
https://jsfiddle.net/ptxsha6m/1/
<script>
var theID = document.getElementById('result1');
function change(){
var checkboxes = document.getElementsByClassName('checkbox');
var chekboxInputs = Array.from(checkboxes).map(a => a.querySelector('input'));
var allAreUnselected = chekboxInputs.every(function(elem){
return !elem.checked;
});
if(allAreUnselected){
chekboxInputs.forEach(function(input){
Array.from(document.querySelectorAll("." + input.getAttribute("rel"))).forEach(function(theID){
theID.style.background = 'blue';
});
});
}
else {
chekboxInputs.forEach(function(input){
Array.from(document.querySelectorAll("." + input.getAttribute("rel"))).forEach(function(theID){
theID.style.background = input.checked ? 'red' : 'gray';
});
});
}
}
change();
</script>
Basically, as I wrote, it should change the div#id with the background yellow to red once a checkbox is selected. But for some reason it insists in targeting the div with class only.
I know there must be something wrong with the logic, there's a few things that I can tell but others I don't understand. For example, at "if(allAreUnselected)" shouldn't it set the background of the yellow box to blue? Since they are all unselected?
All I'm trying to achieve is be able to manipulate the div# inside the function. Any help?
Thanks

Early in your script you capture the DOM element you're talking about in a variable named theID:
var theID = document.getElementById('result1');
Later on, where you're changing the color of the elements, you're using an anonymous function in a forEach, which has a parameter also named theID:
(/* lots of code */).forEach(function(theID){
theID.style.background = 'blue'
});
That parameter name masks the variable defined earlier, so when you use theID inside that function it refers to each of the forEach elements instead of the #result1 element -- and you wind up never attempting to change the color of #result1.
If you want to change the color of that container, either use a different parameter name, so the variable isn't masked by it:
(/* lots of code */).forEach(function(foo){
foo.style.background = 'blue'
theID.style.background = // your logic here for deciding what color #result1 should be
});
...or do it outside the anonymous function:
if(allAreUnselected){
theID.style.background = 'blue';
chekboxInputs.forEach(function(input){
(/* lots of code */).forEach(function(theID){ // (I'd still change that parameter name, though, because masked variables are confusing)

In line 41 what you think is the theID variable is wrong. In this case the variable theID will be shadowed from the variable that the forEach function passes as argument to the callback function(theID){..}.
forEach passes each item in the array as argument to the function you declare on each iteration. Try to change the name of this variable, ex. ...forEach(function(chekboxInput) { chekboxInput.style.background = 'blue';} nothing will change.
From here the theID is not anymore the div with id=result1 but one of the elements in the chekboxInputs that you are iterating on.
See also the answer from Daniel Beck.

Related

Javascript on click event not reading else statement or variables

I'm trying to make a click handler that calls a function; and that function gets a string and basically slices the last character and adds it to the front, and each time you click again it should add the last letter to the front.
It seem so easy at first that I thought I could just do it using array methods.
function scrollString() {
var defaultString = "Learning to Code Javascript Rocks!";
var clickCount = 0;
if (clickCount === 0) {
var stringArray = defaultString.split("");
var lastChar = stringArray.pop();
stringArray.unshift(lastChar);
var newString = stringArray.join('');
clickCount++;
} else {
var newArray = newString.split("");
var newLastChar = newArray.pop();
newArray.unshift(newLastChar);
var newerString = newArray.join("");
clickCount++;
}
document.getElementById('Result').innerHTML = (clickCount === 1) ? newString : newerString;
}
$('#button').on('click', scrollString);
Right now it only works the first time I click, and developer tools says newArray is undefined; also the clickCount stops incrementing. I do not know if it's an issue of scope, or should I take a whole different approach to the problem?
Every time you click you are actually reseting the string. Check the scope!
var str = "Learning to Code Javascript Rocks!";
var button = document.getElementById("button");
var output = document.getElementById("output");
output.innerHTML = str;
button.addEventListener("click", function(e){
str = str.charAt(str.length - 1) + str.substring(0, str.length - 1);
output.innerHTML = str;
});
button{
display: block;
margin: 25px 0;
}
<button id="button">Click Me!</button>
<label id="output"></label>
It is, in fact, a scoping issue. Your counter in inside the function, so each time the function is called, it gets set to 0. If you want a counter that is outside of the scope, and actually keeps a proper count, you will need to abstract it from the function.
If you want to keep it simple, even just moving clickCount above the function should work.
I do not know if it's an issue of scope
Yes, it is an issue of scope, more than one actually.
How?
As pointed out by #thesublimeobject, the counter is inside the function and hence gets reinitialized every time a click event occurs.
Even if you put the counter outside the function, you will still face another scope issue. In the else part of the function, you are manipulation a variable (newString) you initialized inside the if snippet. Since, the if snippet didn't run this time, it will throw the error undefined. (again a scope issue)
A fine approach would be:
take the counter and the defaultString outside the function. If the defaultString gets a value dynamically rather than what you showed in your code, extract its value on page load or any other event like change, etc. rather than passing it inside the function.
Do not assign a new string the result of your manipulation. Instead, assign it to defaultString. This way you probably won't need an if-else loop and a newLastChar to take care of newer results.
Manipulate the assignment to the element accordingly.
You can use Javascript closure functionality.
var scrollString = (function() {
var defaultString = "Learning to Code Javascript Rocks!";
return function() {
// convert the string into array, so that you can use the splice method
defaultString = defaultString.split('');
// get last element
var lastElm = defaultString.splice(defaultString.length - 1, defaultString.length)[0];
// insert last element at start
defaultString.splice(0, 0, lastElm);
// again join the string to make it string
defaultString = defaultString.join('');
document.getElementById('Result').innerHTML = defaultString;
return defaultString;
}
})();
Using this you don't need to declare any variable globally, or any counter element.
To understand Javascript Closures, please refer this:
http://www.w3schools.com/js/js_function_closures.asp

How to increment div id name and localStorage content name using for loop?

I'm trying to run a for loop and increment a number of things here but can't get my head around it
jQuery code
var counter1 = localStorage.getItem('counter1item');
if (counter1 == null){
$("#i1").html('Zero');
} else {
$("#i1").html(counter1);
}
$("#i1").on("click", function(){
counter1++;
$("#i1").html(counter1);
localStorage.setItem('counter1item', $("#i1").html());
});
When I'm use for loop and try to increment everything then it doesn't work:
var i = 0;
for(i=0;i<100;i++){
var counter+"i" = localStorage.getItem('counter+"i"+item');
if (counter+"i" == null){
$("#i"+i).html('Zero');
} else {
$("#i"+i).html(counter+"i");
}
$("#i"+i).on("click", function(){
counter+"i"++;
$("#i"+i).html(counter1);
localStorage.setItem('counter+"i"+item', $("#i"+i).html());
});
}
What am I doing wrong? Any help would appreciated, Thanks.
The problem of your variable definitions has been already explained.
Another problem - When setting click event inside loop, the counter and i variables are overridden each iteration, so that each button will return variable which was set at the end of the loop.
F.ex:
If the loop is: i=0; i<100; i++ , then at the end of the loop i for each button will be always equal to 100. And counter will be always equal to the last set counter +1, because these variables loses their uniqueness outside the loop.
You have to store the i variable somewhere, so that it won't get updated while loop lasts, and is always unique for each button.
I'd store the i in a data-id attribute of the button and set click event on class selector, outside for loop.
Also, since the data is a simple string, you can use .text() instead of .html().
HTML:
<button class="counter" id="i0"></button>
<button class="counter" id="i1"></button>
...
Script:
// no need for this:
//var i = 0;
for(/* i is defined here: */ var i=0; i<10; i++){
var c = localStorage.getItem('counter'+ i +'item');
// add data-id to the element:
$("#i"+i).text(c == null ? 'Zero' : c).data('id',i);
}
// listen for click event on 'counter' class:
$(document).on("click",".counter", function(){
// parse number from text of the button:
var c = $(this).text(parseInt($(this).text())+1 || 1).text();
// grab the id from data-id attribute:
localStorage.setItem('counter'+ $(this).data('id') +'item', c);
});
DEMO
Remove all quotes around the use of variables. Putting them in quotes makes them a string, not your variable (multiple instances of this problem)...
Like this:
'counter+"i"+item'
Literally translates to this string:
counteriitem
Say i = 2, you would write it like so:
'counter'+i+'item'
to result in this string:
counter2item
Also, I don't see the variable counter defined in the second snippet correctly.

If Statement and Function (Basic) keep track on divs innerHTML?

Ok so I have a function set up already and it gets added in the div as numbers and letters
"var elCamLocation = $( "TEST" )"
Right!
Now I want to use a function to keep track on what is in the innerHTML of the "TEST" div and if the contents of the div changes to "0.00x2.00z0.00" then I want it to do something for example lets just say change url to keep it simple.
Here is what I have..
var Numbs = getElementById("TEST").innerHTML;
function TE()
{
if(Numbs = "0.00x2.00z0.00")
{
window.location.assign("http://google.com")
}
};
But it isn't working the window.location.assign("http://google.com")isn't triggering at all
any idea's?
= is for assignment. You should test for equality using the === operator.
if(Numbs === "0.00x2.00z0.00")
{
//etc.
}

Creating Event Listeners for individual DIVS that have not been made yet, and how to trigger the individual command?

I am trying to create clickable divs that will set a variable once they are clicked.
For example,
If my program had to do with playing with balls.
When a user inputs a name, and what kind of ball they want (lets say name= Johnny and Ball=BasketBall) and then clicks "Create a Ball", My program will create a div called "Ball0". The "Ball0" div will display Johnny's name. When a user Clicks on his name it will say "Johnny has a BasketBall.
Here is how I am trying to do this code
var ballRefrence = -1;
function createBall() {
ballRefrence +=1;
var myElement = document.createElement('div');
myElement.id = 'individualBall'+ballRefrence;
ballArea.appendChild(myElement);//ball area is where I want to list the divs
myElement.style.width = "550px";
myElement.innerHTML= userName+" has bought a ball!";
createEventListner();
}
function createEventListner() {
var iBall = document.getElementById("individualBall"+ballRefrence);
iball.addEventListener("click",showBall,false);
}
function playCaption() {
//I am not sure how to pull the individual up here.
//Since I am using the "BallRefrence"variable
//it will always be the last person clicked..
//(Basically I cannot say
//alert.(ballRefrence);
}
I guess what I am trying to say is this,
I have my "BallRefrence" that goes up by 1 each time.
I store all the items in an array. (so first person will go to index 0, second will go to index 1...ect)
I am having problems refrencing the element, because I am not sure how to pull the corrisponding numbe from the div.
Example:
After 3 clicks of "create ball" my html will look something like this.
<div id = "individualBall0></div>
<div id = "individualBall1></div>
<div id = "individualBall2></div>
Since each individual div will match up to the element in the array I want, How will tell my program
"When you click individualBall0, I want ball[0].."
or
"when you click indivdualBall2, I want ball[2]"
I hope this makes more sense.
One solution that doesn't really follow your updated requirements (but I believe does something simpler) is on JSFiddle. This stores the username and ball type in a local closure related to the event listener for that DIV. The code is fairly simple, and it removes some clutter from the global namespace, revealing only createBall:
var createBall = (function() {
var ballReference = -1;
var ballArea = document.getElementById('ballArea');
var showBall = function(userName, ballType) {
return function(event) {
alert(userName + ' has a ' + ballType);
};
};
return function() {
++ballReference;
var userName = document.getElementById('name').value;
var ballType = document.getElementById('ball').value;
var myElement = document.createElement('div');
myElement.id = 'individualBall'+ballReference;
ballArea.appendChild(myElement);
myElement.innerHTML= userName+" has bought a ball!";
myElement.addEventListener("click",showBall(userName, ballType),false);
};
}());
To perform your updated requirements, it should be pretty easy. Your event handler will run in the context of your element, so something like this:
this.id.substring('individualBall'.length) //=> '0', '1', etc
should return a string representing the index of the div. You can use that directly for indexing various arrays, or, if that makes you squeamish, turn it into an integer with parseInt, the Number constructor, or the unary + operator.
But note that the suggestions from Bergi, jfriend00, and RobG are all good. There are many good ways of going about this.

javascript - basic onclick event question

I have a dynamic table populated from an array.
When building the table I have the following inside of a loop:
var tdRecord = trRecord.insertCell(trRow.cells.length);
var tdRecordId = dataArray[j][0];
tdRecord.onclick = function() { alert(tdRecordId); }
The problem is that alert will only alert the last set tdRecordId in the array. If I click on any of the other td rows they all alert the same number.
Anyone know how I can fix this?
This should work:
(function( id ) {
tdRecord.onclick = function() {
alert( id );
};
}( tdRecordID ));
You seem to be running your code inside a loop. In that case, all click handlers will point to the same tdRecordId value. If you want to capture the value of the current iteration, you have to use a function wrapper which will do that for you.
tdRecord.onclick = function () { alert('123'); };
You could use jQuery's data feature: http://jsfiddle.net/zRXS6/.
$(function(){
var number = 1;
var div1 = $('<div>a</div>');
div1.data('number', number);
div1.click(function() {window.alert($(this).data('number'))});
number = 2;
var div2 = $('<div>b</div>');
div2.data('number', number);
div2.click(function() {window.alert($(this).data('number'))});
$('body').append(div1).append(div2);
});
tdRecord.onclick = "alert(" + tdRecordId + ")";
Set it as a literal, rather then a dynamic. :)
In what you're doing, it will always refer to the variable, rather then the current value.
So as the variable changes, what the function alerts will change.
In this, it actually inserts the value, rather then the variable itself, so it will stay the same instead of changing.

Categories

Resources