Javascript variable is undefined - javascript

<html>
<head>
<title>Array of images</title>
<script type="text/javascript">
var myPics = new Array[3];
myPics[0] = "./img/blue.png";
myPics[1] = "./img/red.png";
myPics[2] = "./img/yellow.png";
var counter = 0;
function preImg(){
alert(counter);
if(counter == 0)
counter = 4;
counter --;
alert(counter);
document.getElementById("coloredImg").src = myPics[counter];
}
function nextImg(){
if(counter == 3)
counter = -1;
counter ++;
document.getElementById("coloredImg").src = myPics[counter];
}
</script>
</head>
<body>
<img src="./img/blue.png" id="coloredImg" alt="Image not found"/>
<input type="button" onclick="preImg()" value="Previous"/>
<input type="button" onclick="nextImg()" value="Next"/>
</body>
</html>
The problem I encounter is that my counter variable is undefined inside the function. For example when I call the function preImg it alerts me with undefined (when it should be just 0) and the second alert show NaN when it should be a 3. Why my function doesnt recognize my "var counter" it is global isnt it? Do you think the same happens with the variable mypics. Thanks!

new Array[3];
should be
new Array(3);
But rather, use the square bracket notation to create an array (there's no need to specify the length either):
var myPics = [];
Why use this syntax you may ask? There are many reasons:
[] is a faster and shorter way of creating an array.
The Array constructor can be overridden while a syntactical construct like this cannot.
It's much easier to spot in code, making debugging easier.
It has the ability to take a single element (i.e [5]) and not interpret it as the length of the array, a common problem with the cumbersome Array constructor.

var myPics = new Array[3]; should be var myPics = new Array(3);
JsFiddle: http://jsfiddle.net/cbJAc/

Simple slideshow object using a closure over element, pics and counter:
function Slideshow(element, pics) {
var counter = 0;
this.nextImg = function () {
element.src = pics[counter];
counter = (counter + 1) % pics.length;
}
this.nextImg(); // init
}
usage:
var show = new Slideshow(
document.getElementById("coloredImg"),
["./img/blue.png", "./img/red.png", "./img/yellow.png"]
);
show.nextImg(); // red
show.nextImg(); // yellow
show.nextImg(); // blue
Closures make sure that every variable that's in scope when a function is defined will still be in scope when the function is called (or called again). This standard JavaScript technique elegantly solves your counter issue.
Using a modulus based calculation lets the counter repeat the sequence 0,1,2 (in this example).
Edit: Assume you would want to switch to a new image every three seconds:
setInterval(show.nextImg, 3000);

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

Understanding loops in Java Script

This is my code, I'm not sure whether I am using the correct loop but this is basically want to do. I am trying get every src in the array to print out every one second, but the myPix[thisPic] becomes undefined when attempting to print out the second item in the myPix Array. I'd really be happy to get some help. Thank you!
function nextPic() {
count = -1;
thisPic = 0;
if (thisPic == count) {
document.write("This shouldn't ever happen");
return false;
} else {
count++;
var myPix = new Array("images/slideshow/Jellyfish.jpg", "images/slideshow/Penguins.jpg", "images/slideshow/Lighthouse.jpg");
slideTag = document.getElementsByTagName("img")[1];
slideTag.src = myPix[thisPic];
currPic = slideTag.src;
document.write(myPix[thisPic] + "<br />");
document.write(currPic);
}
return false;
}
setInterval(nextPic, 1000);
Code doesn't work because "loop" has no shared variables. Every iteration should work on the same array and the same iterator, in Your code every iteration created new array and new iterator, so every iteration was doing the same thing.
To work correctly every loop iteration must:
Take current image src from array ( one variable declared outside loop )
Set it on img element
Change current variable to current+1 ( current variable delared outside loop )
If our current is more that array size then - end (clearInterval) or set current on 0 - then will start again and again ...
//array declaration should be outside of loop
var myPix = new Array("https://www.gravatar.com/avatar/50fbdd1dcbe4763a33a0e212f6a632c8?s=32&d=identicon&r=PG&f=1", "https://www.gravatar.com/avatar/5be6299fb284071a9fd2cc2cc0b9090a?s=32&d=identicon&r=PG", "https://i.stack.imgur.com/mlB9c.jpg?s=48&g=1");
var currentPic=0; //this is number of current picture
function nextPic(){
if (currentPic>= myPix.length){
// here example how to stop:
//clearInterval(interval);
//return;
//we loop it over again from begging
currentPic=0;
}
//get img in page - image by currentPic
slideTag = document.getElementsByTagName("img")[1];//second
//set src on this slideTag from array
slideTag.src = myPix[currentPic];
currentPic++;
}
var interval=setInterval (nextPic, 1000);//save interval in variable to use it to stop
<h1>images</h1>
<img><br/>
<img><br/>
<img><br/>
I taken example avatars from stackoverflow to show working example :)
As per understanding your code, I have figurout your issue
var myPix = ["images/slideshow/Jellyfish.jpg", "images/slideshow/Penguins.jpg", "images/slideshow/Lighthouse.jpg"];
counter=0;
interval = setInterval (nextPic, 1000);
function nextPic(){
if(counter >= myPix.length){
document.write("This shouldn't ever happen");
clearInterval(interval);
}
else{
slideTag = document.getElementsByTagName("img")[1];
slideTag.src = myPix[counter];
currPic = slideTag.src;
document.write(myPix[thisPic] + "<br />");
document.write(currPic);
counter++;
}
}

setInterval() change image

The goal: When the page is loaded, display the image andy_black.jpg. After two seconds, change the image source, and the thus image in the browser, to a second image called andy_white.jpg. This will change back and forth every 2 seconds.
I checked out this article:
SetInterval function calls
(I searched other as well, with the tags [javascript] [function] and the word "setinterval", but most were using jQuery and my intention here is not to use any jQuery, it's an experiment in JavaScript after all).
which was quite helpful for before I had read it my code was much longer and the function was not called in the setInterval() function.
So here's some code:
Suggestions?
var i = 1;
function change_pic() {
i + 1;
if (i == 5) {
i = 1;
}
//I suspect the computer will read i as 5 for some
//tiny amount of time before reverting back to 1
//which I suspect could cause a further problem, but
//is it the source of the current issue?
if (i == 1 || i == 2) {
document.getElementById('img_to_flip').src = "https://cdns-images.dzcdn.net/images/artist/5d9e44027cc266260d7bd932d98f739d/500x500.jpg";
} else {
document.getElementById('img_to_flip').src = "https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg";
}
}
var pic_src = setInterval(change_pic, 2000);
<img id="img_to_flip" src="https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg" height="100" width="100" />
You forget to actually reassign the new value to i.
Either use:
i = i + 1;
or
++i;
Also, why count to five when you only have two states? A common paradigm to have an auto-resetting counter is to use modulo arithmetic:
i = (i + 1) % 2;
which guarantees that i will only ever have values of 0 or 1.
FWIW, here's an alternate way of writing the entire feature that'll work for any number of images - just populate the pics array:
(function() { // function expression closure to contain variables
var i = 0;
var pics = ["https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg", "https://cdns-images.dzcdn.net/images/artist/5d9e44027cc266260d7bd932d98f739d/500x500.jpg"];
var el = document.getElementById('img_to_flip'); // el doesn't change
function toggle() {
el.src = pics[i]; // set the image
i = (i + 1) % pics.length; // update the counter
}
setInterval(toggle, 2000);
})(); // invoke the function expression
<img id="img_to_flip" src="https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg" height="100" width="100" />
If you want to avoid the delay in first time setInterval call the function before the setInterval as shown in the top answer:
(function() { // function expression closure to contain variables
var i = 0;
var pics = [ "andy_white.jpg", "andy_black.jpg" ];
var el = document.getElementById('img_to_flip');
function toggle() {
el.src = pics[i]; // set the image
i = (i + 1) % pics.length; // update the counter
}
toggle()
setInterval(toggle, 2000);
})(); // invoke the function expression

Changing global Variable from within function

Here im having a bit of an issue with this very simple script Ive written up. The aim for this script is to simply reduce the given number by one each time the button is clicked. I cannot appear to do this.. My global variable being the Number=100 doesnt appear to change, or change more than once.. Apologies for not being able to explain this well.
Here is the part im working on..:
<script>
var Number = 100; // Number i want changed and to keep changing each button click
function outcome() { // Button calls this function
Number = Number - 1; // Tries to change Global Number.. :/
}
document.write(Number); // Has the Number written in the document
</script>
Yes, conceptually this is right. Only you are not calling the function, at least not before writing Number to the document.
Btw, Number is the global reference to the Number constructor so you should use another variable name, lowercase at best.
var num = 100;
function outcome() {
num--;
}
outcome();
document.write(num); // 99
or
<script>
var num = 100;
function outcome() {
num--;
alert(num);
}
</script>
<button onclick="outcome()">Decrease!</button>
(Demo at jsfiddle.net)
You have to call your function:
<script>
var Number=100
function outcome(){
Number=Number-1
}
outcome(); // call the function here
document.write(Number)
</script>
or don't use a function in the first place:
<script>
var Number=100
Number=Number-1
document.write(Number)
</script>

Dynamic variable names with Javascript and constructor: cloning an image with EaselJS dynamically to multiple canvases

Good day!
I'm here to ask help about dynamic variable names in Javascript applied to a constructor. It's been much more difficult than expected. I've read about this issue in numerous forums and webpages but I can't find what I'm doing wrong =/
I'm using a HTML5+Javascript library called EaselJS but my problem it's not related to it but to Javascript syntaxis!
Here's my problem. I got this code:
stage1 = new Stage(document.getElementById("cnvs1"));
stage2 = new Stage(document.getElementById("cnvs2"));
stage3 = new Stage(document.getElementById("cnvs3"));
Here, the variables stage have assigned an Stage object which is initialized with canvas id cnvs This line (in the context of the rest of my code) works!
I'd like to simplify this to a single line with a for like this:
for(i = 0; i < 5; i++){
//Of course this is wrong!
stage[i] = new Stage(document.getElementById("cnvs[i]"));
}
This link here resumes how this can be done: With eval (a lot of people say it's not recommendable) and with window (recommended) Then if I do this (without the for to simplify even more):
var varname = "stage";
var i = 1;
window[varname + i] = new Stage(document.getElementById("cnvs_terminal1"));
The code still works. But I can't figure out how to accomplish a similar solution with the canvas id in quotes. These lines of code fail:
var i = 1;
var varname = "stage";
var varname2 = 'cnvs1';
var varname3 = "\"cnvs1\"";
var varname4 = "\"cnvs1" + i + "\"";
window[varname +i] = new Stage(document.getElementById(window[varname2]));
window[varname +i] = new Stage(document.getElementById(window[varname3]));
window[varname +i] = new Stage(document.getElementById(window[varname4]));
In these attempts even trying to pass the exact value I need (without the i) it's not helping me!! I'm backslashing quotes because I think they are necessary for the getElementbyId=( =( =(
Now I'm clueless! =(
I'm certain there is a way to do this, maybe I don't know the syntax, maybe I don't know how to call variables with reference or by value properly, I don't know...
Please help me, I don't know how to do this simple task!
THANKS A LOT =)
EDIT:
Trying #cHao suggestion I can't do it either! Keeping it simple, I set the for for i to be one only:
for (var i = 1; i <= 1; ++i) {
//I use only one of the following lines at a time of course, but I'll write here my failing tries all together:
stage[i] = new Stage(document.getElementById('cnvs'+i));
stage[i-1] = new Stage(document.getElementById('cnvs'+i));
//Hardcoding the first variable works!
stage1 = new Stage(document.getElementById('cnvs'+i));
}
Half of the problem it's solved, but what to do with the first variable? =/ THANKS!!!!
EDIT 2:
More detail has been requested! Here's a copy/paste example! Just update the EaselJS and an image paths for this to work!
<!DOCTYPE HTML>
<html>
<head>
<script src="easeljs-0.4.0-26/lib/easel.js"></script>
<script type="text/javascript">
function init() {
//MY PROBLEM LIES HERE!!
for (var i = 1; i <= 1; ++i) {
//This code WORKS
stage1 = new Stage(document.getElementById('cnvs'+i));
//This code DOES NOT WORKS
//stage[i] = new Stage(document.getElementById('cnvs'+i));
//stage[i-1] = new Stage(document.getElementById('cnvs'+i));
}
var images = "images/itzapic.jpg";
bitmap = new Bitmap(images);
stage1.addChild(bitmap);
stage1.update();
Ticker.addListener(window);
}
function tick() {
stage1.update();
}
</script>
</head>
<body onload="init()">
<canvas id="cnvs1" width="140" height="82">
</body>
</html>
___________________________________________
EDIT 3: SOLVED!
I'll post the final code for reference to someone who want to use EaselJS to render a single image in as many canvases as needed with the same object. For this you'll need the bitmap.clone() method and arrays for the stages. Thanks to #cHao for helping me out ;)
The following code will render the same image in all canvases! Update as necessary ;)
<!DOCTYPE HTML>
<html>
<head>
<script src="easeljs-0.4.0-26/lib/easel.js"></script>
<script type="text/javascript">
stage = [];
function init() {
for (var i = 1; i <= 6; ++i) {
stage[i-1] = new Stage(document.getElementById('cnvs'+i));
}
var images = "images/itzapic.jpg";
bitmap = new Bitmap(images);
stage[0].addChild(bitmap);
for (var i = 1; i <= 5; ++i) {
stage[i].addChild(bitmap.clone());
}
stage[0].update();
Ticker.addListener(window);
}
function tick() {
for (var i = 0; i < stage.length; ++i) {
stage[i].update();
}
}
</script>
</head>
<body onload="init()">
<canvas id="cnvs1" width="140" height="82"></canvas>
<canvas id="cnvs2" width="140" height="82"></canvas>
<canvas id="cnvs3" width="140" height="82"></canvas>
<canvas id="cnvs4" width="140" height="82"></canvas>
<canvas id="cnvs5" width="140" height="82"></canvas>
<canvas id="cnvs6" width="140" height="82"></canvas>
</body>
</html>
Not sure i get the point of eval'ing or pre-figuring variable names and all that. Seems like you could just do like
for (var i = 1; i <= 5; ++i) {
stage[i] = new Stage(document.getElementById('cnvs' + i));
}
window["varname"] won't help unless varname is global, and...eh. You'll want to avoid globals if you can. Either way, you don't need to escape quotes -- you don't need quotes in the name itself at all unless your IDs have quotes in them (which, AFAIK is invalid anyway) or you're eval'ing (which is evil in itself).
If you're looking to put the stages into an array (which seems like a better goal), you'll want your first stage to be stage[0]. In which case, set stage[i-1] instead of stage[i].
And if you're trying to set stage1, stage2, etc...stop. Don't do that. You have a bunch of items, that you're treating alike...that's the kind of thing arrays were meant for. For one thing, notice how much easier it is to work with array elements than similarly-named variables? I wasn't even seeing the issue, because with arrays it's already a non-issue.
As for your code...watch this.
stage = [];
function init() {
for (var i = 1; i <= 1; ++i) {
stage[i-1] = new Stage(document.getElementById('cnvs'+i));
}
var images = "images/itzapic.jpg";
bitmap = new Bitmap(images);
stage[0].addChild(bitmap);
stage[0].update();
Ticker.addListener(window);
}
function tick() {
for (var i = 0; i < stage.length; ++i) {
stage[i].update();
}
}
Once we switch from the stage1 stage2 brokenness to using an array, now we can have as many stages as we want.
I think you want this:
var stagePrefix = 'stage';
var canvasPrefix = 'cnvs';
//adjust loop below based on your naming e.g. do they start at 0 or 1?
for(var i=1;i<5;i++){
window[stagePrefix + i] = new Stage(document.getElementById(canvasPrefix + i));
}
Rather than using an id with a numeric suffix to reference your canvases, I'd get them by tag name:
var canvases = document.getElementsByTagName("canvas");
Or, if you only want to process a certain set of the canvas elements on the page, give them a class:
var canvases = document.getElementsByClassName("cnvs");
Then, to get an Array of stages from your canvases, hijack the Array.map()* method:
var stages = [].map.call(canvases, function(canvas) {
return new Stage(canvas);
});
*Array.map() is new to JS5, but if your browser supports <canvas> it supports JS5. Regardless, here's the link to an implementation of Array.map() you can use to support older browsers, in case you do have to support older browsers and you aren't already using a JS5 shim.

Categories

Resources