I've been working on making a basic little image carousel in jQuery.
Currently at the moment I am stuck on the if else logic inside of my changeImage function.
When the user clicks on the "next" link then the next image in line should fade in. Luckily when I comment out the if else statement I'm able to achieve the images fading out but this is not what I am after. So we know it's a logic issue.
I'm just not sure how to implement the correct syntax with combining conditions within my if else statement and I'm sure this logic could also be much cleaner.
Please review
function changeImage (newIndex) {
var i = newIndex;
var current = i;
// `if` user clicks on next then slide image "right"
// something wrong here with my logic..
if ((newIndex === 'next') && i === (current < lengthOfImages - 1)) {
return current + 1;
}
else {
return 0;
}
// fadeout
listOfImages.fadeOut(transitionSpeed).
eq(i).fadeIn(transitionSpeed);
}
// click function on the next link
$('.next').on('click',function() {
changeImage('next');
});
Some feed back on how to fix this with a few hints towards a solution would be greatly appreciated.
JSFiddle
http://jsfiddle.net/kapena/v82pvq7x/1/
Return statement will exit the function. Anything after it will NOT run. If you want to actually return the number, you need to do it at the end.
I think you actually want to set current and not to return. Also your logic really does not make any sense. Most people would do the check like this:
current++;
if (current >= lengthOfImages) {
current = 0;
}
When 'Next' is clicked, the following is happening:
changeImage is fired, passing in 'next' as its parameter.
Within this function, a variable of i is declared and set as 'next'.
A variable of current is also being set to i, which is currently set to 'next'.
Your if statement checks to see if newIndex(the passed in parameter) is equal to 'next' as well as if i is equal to a boolean of current < lengthOfImages - 1. This is evaluating to a boolean, and i is not a boolean. This is why your function is not firing appropriately.
Your return statements in your conditionals are causing your function to complete, making it so your fadeOut and fadeIn transitions never get a chance to execute.
This part
if ((newIndex === 'next') && i === (current < lengthOfImages - 1))
is always false:
i = 'next'
current = 'next'
(current < lengthOfImages - 1) is a boolean
therefore the === is always false, and flow goes to the return clause.
Related
I use Foundation.MediaQuery.current to determine current breakpoint. Every time I call console.log(Foundation.MediaQuery.current) for the first time (n=0) I get nothing.
For all next calls (n>0) I always get correct breakpoint, let's say large.
This is my function:
_calculateLimit = function () {
var postsInjectedCount = container.find('.post-appended').length;
console.log(Foundation.MediaQuery.current);
if (Foundation.MediaQuery.current === 'large') { // gives nothing on first iteration :/
return postsInjectedCount % 3 !== 0 ? 2 : 3;
}
return postsInjectedCount % 2 !== 0 ? 1 : 2;
},
Below picture shows a screen from my Chrome Dev Tools.
Helpful info 1: There is no difference in terms of business logic between first call and next calls.
Helpful info 2: I use Foundation For Sites ~6.2.1
What am I doing wrong?
It looks like you are running the code before Foundation has initialized. It is a good practice to put the init code at the top of JavaScript file.
You will see it better if put the console.log at the end of the function. So try it and just tell the results.
It will clarify where the error is.
This is my code:
var counter = 0;
function showAddButton() {
var cnt = document.getElementsByClassName('img-cntnr').length;
counter++; // for detecting double excecution in debugger
if (cnt < 4) {
$('#div-add').show();
} else {
$('#div-add').hide();
}
}
//someweher in my code
showAddButton();
when I call function in my code, JavaScript executes both $('#div-add').show(); and $('#div-add').hide(); lines.
I've defined a variable (counter) and watched that in debugger for detecting parallel twice call. but there is not any parallel execution and in first call if-statement executes both blocks!
how can I fix that?
Thank You.
Your issue is most likely your if statement is not the logic you want perhaps your < should be a >, because even if you were hitting it multiple times that shouldn't really effect the results of the problem because the only way for the else to hit would be if you count was actually greater than what you expected.
So either something else is hiding the div, something is modifying the class count, or your logic is not what you expected it to be.
However you can try this line of code which will get rid of all the excess logic you have
$('#div-add').toggle($('.img-cntnr').length < 4)
you can use a boolean in the toggle fuction to set the display
you can see the toggle documentation here
Here look at this jsFiddle
I cannot see any duplicate calls, nor that both blocks of if/else are executed in one call.
showAddButton always shows element because it depends on:
document.getElementsByClassName('img-cntnr').length;
which gets length of how many elements matched img-cntnr class. So, unless you are adding elements with that class to the DOM, that count will always be the same.
If you can show us jsFiddle that prints both show and hide we will have something to go by.
There is definitely something else that is causing the code to run again. What I would do is add a killer to your js and modify the else statement to look like this:
var counter = 0;
var killer = false;
function showAddButton() {
var cnt = document.getElementsByClassName('img-cntnr').length;
counter++; // for detecting double excecution in debugger
if (cnt < 4) {
$('#div-add').show();
killer = true
} else if(killer === false) {
$('#div-add').hide();
}
}
//someweher in my code
showAddButton();
Right now I have a few issues I need to tweak out with my Quiz Application.
When the user answers the first question, he can skip the proceeding questions.
var usersGuess = -1; //this is the starting value of the userGuess variable
This is because the userGuess variable is updated by the id of the radio button clicked when the user makes a guess, and the default starting variable is what prevents the user from skipping the first question only. I have a few ideas on how to fix it, but not sure how to implement it. One would be to detect IF none of the radio inputs are checked then don't load the next question, else load it.
When a user goes back to the question, the previous checked radio button disappears. I haven't thought of how to fix this yet. Right now I have saved the previous answers into an empty array, but I don't believe it's working properly.
Here is the code that deals with userGuess and how it interacts with the Event Listener for my next button.
nextButton.addEventListener('click', function() {
//prevent user from skipping questions
if (usersGuess === -1) {
console.log(usersGuess);
alert('You must choose an answer!');
} else {
//if users guess is the id of the correct answer, add one
if (usersGuess == questions[index].correctAnswer) {
userScore += 1;
console.log('Users Score: ' + userScore);
}
//store previous user answers into an array
usersAnswers.push(usersGuess);
if (index + 1 < questions.length) {
index++;
addQuizQuestion(questions[index].question);
addQuizAnswers(questions[index].choices);
} else {
alert('You scored a ' + getPercent() + '%!');
}
}
}, false);
Here is a link to the codepen as well for testing: http://codepen.io/laere/pen/KVwBME
Appreciate the help!
Don't complicate things too much. All you need here is the index of the current question and, say, an array of boolean (or integers, for points) for each question.
All you need to do is to check whether the current question has been answered, and if so, allow the user to move on.
Of course, since this is Javascript, all this serves for a better user experience and nothing more - if someone WANTS to move on to the next question, they WILL (unless you implement some server-side checking/question loading).
reset usersGuess to -1 before loading next question.
if (index + 1 < questions.length) {
index++;
usersGuess = -1; // reset usersGuess
addQuizQuestion(questions[index].question);
addQuizAnswers(questions[index].choices);
}
I am admittedly a super newbie to programming in general. I am trying to design a quick piece of javascript to inject on a website for a class that will both uncheck and simulate a click on a series of checkboxes. This is nothing malicious, the web form we use to download data for use in this class presents way more variables than necessary, and it would be a lot more convenient if we could 'uncheck' all and only check the ones we want. However, simply unchecking the boxes via javascript injection doesn't yield the desired result. A mouse click must be simulated on each box. I have been trying to use the .click() function to no avail. Any help is greatly appreciated. My code below fails with an error of:
"TypeError: Cannot read property 'click' of null"
CODE:
var getInputs = document.getElementsByTagName("input");
for (var i = 0, max = getInputs.length; i < max; i++){
if (getInputs[i].type === 'checkbox')
getInputs[i].checked = false;
document.getElementById('shr_SUBJECT=VC' + i).click();
}
--------EDIT#1--------------
FYI, this is the website that I am trying to use this on:
http://factfinder2.census.gov/faces/nav/jsf/pages/searchresults.xhtml
if you search for and open up any of these tables they are huge. It would be awesome if I could easily pare down the variables by 'unchecking' and 'clicking' them all at once via javascript.
The code at the bottom ALMOST works.
The problem I am running into now is that it throws an error after the first or second run through the for loop:
"TypeError: document.getElementById(...) is null"
I understand that this is because the value it's trying to find doesn't exist? Sometimes on these tables the checkboxes are greyed out/don't exist or are otherwise 'unclickable'. My theory as to why I am getting this error is because in the table/form the 'available' ID's will start around:
shr_SUBJECT=VC03 or sh_SUBJECT=VC04
and it may then skip to:
shr_SUBJECT=VC06 then skip to shr_SUBJECT=VC09 and so on...
So if the for loop hits an ID that isn't available such as 05 or 07, it returns a null error :(
I did some reading and learned that javascript is able to 'catch' errors that are 'thrown' at it? My question now is that I'm wondering if there is an easy way to simply iterate to the next ID in line if this error is thrown.
Again, any and all help is appreciated, you guys are awesome.
OLD DRAFT OF SCRIPT
var getInputs = document.getElementsByTagName("input");
for (var i = 3, max = getInputs.length; i < max; i++){
if (getInputs[i].type === 'checkbox' && i < 10){
var count = i;
var endid = count.toString();
var begid = "shr_SUBJECT=VC0";
var fullid = begid.concat(endid);
document.getElementById(fullid).click();
}
else if(getInputs[i].type === 'checkbox' && i >= 10){
var count = i ;
var endid = count.toString();
var begid = "shr_SUBJECT=VC";
var fullid = begid.concat(endid);
document.getElementById(fullid).click();
}
}
--------EDIT#2----------
An example of a table that I am trying to manipulate can be found at this URL:
http://factfinder2.census.gov/faces/tableservices/jsf/pages/productview.xhtml?pid=ACS_12_5YR_DP02&prodType=table#
If you click on the 'Modify Table' button, you are able to select/deselect specific variables via the checkboxes. If you right-click on a couple of 'active' checkboxes and inspect the elements, and it looks something like this:
<input id="shr_SUBJECT=VC03" checked="" alt="hide SUBJECT=VC03" name="" value="" onclick="javascript:hiderow('SUBJECT=VC03');" type="checkbox">
<input id="shr_SUBJECT=VC25" checked="" alt="hide SUBJECT=VC25" name="" value="" onclick="javascript:hiderow('SUBJECT=VC25');" type="checkbox">
Thank you so much #Jonathan Steinbeck for the tip about the ternary operator, it really cleaned up my code.
The script works properly, but the problem I am running into now is that it doesn't iterate enough times after the try, catch statement. If there is a gap in the id #'s; say it jumps from shr_SUBJECT=VC19 to shr_SUBJECT=VC=24 the script will stop running. Is there a way to make it keep retrying the try/catch until it gets a valid ID # or one that exists/is an active checkbox?
CURRENT DRAFT OF SCRIPT :
var getInputs = document.getElementsByTagName("input");
for (var i = 3, max = getInputs.length; i < max; i += 1) {
try {
if (getInputs[i].type === 'checkbox'){
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
}
}
catch (err) {
i+=1;
if (getInputs[i].type === 'checkbox'){
if (getInputs[i].type === 'checkbox'){
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
}
}
}
}
When you call document.getElementById() with a non-existing ID, null is returned. Therefore this error means that you're trying to call the .click() method on null, which can't work.
So you should check what the correct ID naming scheme for the elements you want is. Maybe the elements' count starts with 1 instead of 0?
Also, the .click() doesn't work for all elements like you would expect as far as I know. So depending on the kind of element you are trying to retrieve you might have to create and dispatch your own event as suggested by RobG's comment.
EDIT in response to your recent edit:
You can wrap code that throws errors in a try-catch like this:
for (var i = 3, max = getInputs.length; i < max; i += 1) {
try {
document.getElementById("the_ID").click();
}
catch (error) {
console.error(error);
// continue stops the current execution of the loop body and continues
// with the next iteration step
continue;
}
// any code here will only be executed if there's not been an error thrown
// in the try block because of the continue in the catch block
}
Also, what are you doing with the 'i' variable? It doesn't make sense to assign it to so many variables. This does the same:
document.getElementById("shr_SUBJECT=VC" + (i < 10 ? "0" : "") + i).click();
The ... ? ... : ... is an operator (called the 'ternary operator') that works like this: evaluate the expression before the "?" - if it results in a truthy value, the expression between "?" and ":" is evaluated and becomes the result of using the operator; if the condition results to false, the part after the ":" is evaluated as the value of the operator instead. So while "if" is a statement in JavaScript (and statements usually don't result in a value), the ternary operator can be used as an expression because it results in a value.
By concatenating a string with something else, you are forcing the 'something else' to be converted to string. So an expression like this will usually result in a string:
"" + someNonStringVar
Also, it doesn't make sense to define variables in a loop body in JavaScript. JavaScript variables have function scope, not block scope. What this means is that any variables defined in the loop body exist inside the whole function as well. Therefore it is recommended to write all of the "var"s at the top of your function to make it clear what their scope is. This behaviour of JavaScript is called 'hoisting', by the way.
I've furthermore taken a look at the URL you've given in your recent edit but I fail to find the kind of naming scheme for IDs you describe. In which table did you find those?
Edit in response to your second edit:
You shouldn't mess with the 'i' variable inside the body of a for loop. It makes your code much harder to reason about and is probably not what you want to do anyway. You don't need to handle the next step of the iteration in the catch block. The 'i' variable is incremented even if there's an error during fetching the element from the DOM. That's why you use catch in the first place.
I have a jQuery plugin with an if statement in it.
For some strange reason (probably it is just me screwing things up) it always gets in the else part even when the url's are the same.
if (opts.startUrl == track.permalink.url) {
var active = true;
} else {
alert('|'+opts.startUrl+'| |'+track.permalink_url+'|');
var active = false;
}
Check it out # http://dev.upcoming-djs.com
The surrounding code uses track.permalink_url, while the if block evaluates track.permalink.url (which is always undefined), so this condition:
opts.startUrl == track.permalink.url
Always evaluates to false
Update: as #brianpeiris points out, the correct fix here would be to change the condition to:
opts.startUrl == track.permalink_url
Start printing both the values and see what is the difference , otherwise do this
if (opts.startUrl.toLowerCase() == track.permalink.url.toLowerCase())