Incorrect array value - javascript

I have an array (spliced to size 2) that keeps track of what user click (first, last). first and last elements are unique.
I am trying to load content based on what user clicked. The weird thing that is happening is that I don't see the updated array unless I do 2 console.logs. If 1 log is done the array doesn't get updated. I'm guessing this has something to do with array execution/manipulation time.
The way I debug is to a click handler to document and click to see the array value. Any suggestions or tips?
I never had this issue before. Thanks.
var clicksInfo = [];
$('#a, #b, #c').on('click', function(e){
// array: add, splice
if(jQuery.inArray($(this).attr('id'), clicksInfo) == -1){
clicksInfo.push($(this).attr('id'));
if(clicksInfo.length == 2){
// might do something
}else if(clicksInfo.length == 3){
clicksInfo.splice(0,1);
}
}else{
clicksInfo.splice(0,1);
clicksInfo.push($(this).attr('id'));
}
if($(this).attr('id') == 'a'){
// do stuff.
}else if($(this).attr('id') == 'b'){
// do stuff.
}else if($(this).attr('id') == 'c'){
// do stuff.
}
});
$(document).on('click', function(){
console.log('clicksInfo', clicksInfo);
// console.log('clicksInfo', clicksInfo);
});

Strings are strings, arrays are arrays, even in a console.log, so when doing :
console.log('clicksInfo', clicksInfo);
thats a string, a comma, and then an array ?
try doing:
console.log('clicksInfo : '+ clicksInfo);
to show the string representation, or to show the array as an object, don't mix it with other strangeness:
console.log(clicksInfo);

The problem you are facing is that events that occur are not guaranteed to execute in a specific order. Either click handler could be executed first, though in most browsers your handler for #a, #b, #c would be executed first.
While you could try to use setTimeout to wait long enough to synchronize your data, your code is quite likely to break.
If you want to handle a click in both cases, my recommendation would be to remove the handler for #a, #b, and #c. Use the document click handler only, pass in the event declaration, and then check the ID of the clicked element in your handler to invoke the first code. You are then guaranteed to have updated data before your second block of code runs. Something like this:
var clicksInfo = [];
$(document).on('click', function(e){
if (e.target.id === "a" || e.target.id === "b" || e.target.id === "c") {
// array: add, splice
if (jQuery.inArray(e.target.id, clicksInfo) == -1){
clicksInfo.push(e.target.id);
if(clicksInfo.length == 2){
// might do something
} else if(clicksInfo.length == 3){
clicksInfo.splice(0,1);
}
} else {
clicksInfo.splice(0,1);
clicksInfo.push(e.target.id);
}
if(e.target.id === 'a'){
// do stuff.
}else if(e.target.id === 'b'){
// do stuff.
}else if(e.target.id === 'c'){
// do stuff.
}
}
console.log('clicksInfo', clicksInfo);
});
JSFiddle here.

Related

Determining whenever user checks or unchecks a checkbox

Here is my Code:
$(document).ready(function () {
$("input[type='checkbox'][name='mycheckboxname']").change(function () {
if ($(this).checked == true) {
//do something (script 1)
}
else {
//do something else (script 2)
}
})
});
What i want to accomplish is to have 2 scripts running depening whenever user checks or unchecks a "mycheckboxname" checkbox.
Problem is that with above code i get always only script 2 to run so it looks like if $(this).checked is always false even if user checks the checkbox. Am I using $(this) the wrong way?
checked is a DOM property of the element, but $(this) returns a jQuery object.
You could just use the DOM property:
if (this.checked)
There's no reason to wrap this in a jQuery instance for that. I mean, you can:
if ($(this).prop("checked"))
...but it doesn't do anything useful on top of this.checked.
Side note:
if (someBoolean == true)
is just a roundabout way of writing
if (someBoolean)
I mean, why stop there? Why not
if ((someBoolean == true) == true)
or
if (((someBoolean == true) == true) == true)
or... ;-)
Use $(this).prop("checked") to get the true/false value of a <input type="checkbox">
Click the run code snippet below to see it work
$("input[type=checkbox]").change(function(event) {
if ($(this).prop("checked") === true) {
alert("ON");
}
else {
alert("OFF");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox">click it

jQuery multi vals required

I am trying to show a field, which is hidden, but shows up when 2 previous fields are filled.
$('#planner-locatie-ehv').change(function() {
if ($("#planner-locatie-ehv").val() == "Requirement1" && $("#planner-stad").val() == "Requirement2") {
$("#hideentertainment").show();
}
else {
$("#hideentertainment").hide();
}
});
But the field which is called #hideentertainment won't show up, although the previous fields has Requirement1 and Requirement2, when i use the OR statement ||, it does work, when 1 value is filled in it shows up. How can i make this possible?
You need to listen on both elements, not just the first one.
$('#planner-locatie-ehv, #planner-stad').change(function() {
var isValid = $("#planner-locatie-ehv").val() == "Requirement1" && $("#planner-stad").val() == "Requirement2";
$("#hideentertainment").toggle(isValid);
});
#dandavis is correct. It's only watching the first one for change. You can add the other to your selector to fix it.
$('#planner-locatie-ehv, #planner-stad').change(function() {
if ($("#planner-locatie-ehv").val() == "Requirement1" && $("#planner-stad").val() == "Requirement2") {
$("#hideentertainment").show();
}
else {
$("#hideentertainment").hide();
}
});

Can't find the bug - too many firings

(edited some spelling errors)
So here's a piece of code that repeats itself with every answer the user gives to an MPC-question:
It fires the question, generates 4 answers, binds 'click' and 'mouseover' to the answers, and waits for the user to actually click on one of them.
When he does, it checks if it was right or wrong, displays that to the user, and then waits for another input (anywhere in the document, this time) before it proceeds and repeats.
Now, the idea is that a user can either click with the cursor, OR use QWER to answer. And as I'm am quite new to manipulation of an event and its data, I found a (flawed, apparently) way to separate the two, as you'll find below.
However, when a user 'answers' by clicking, and 'proceeds' by QWER, it waltzes through the whole thing too fast, by actually firing the question as intended, and then immediately answering it AND firing another question AGAIN. (And after extracting the time it takes for this into an array, I found that it sometimes does this 3-6 times in a row, with no apparent reason for this how many times at all...)
Now, as mentioned, I am new when it comes to events, so there may be redundancies and/or wrong uses of (e), but bear with me. I expect the bug to be related to this, of course. Also, some functions are irrelevant here, because they lead back to whatever function their call is in (right(); for example, does not fire anything after itself).
It's the loop that's the point here.
Thanks in advance!
Here's the code:
function keyAns() {
answered="no";
draw(0);
}
function keyNotAns (A) {
B = $(A).children('.answer');
if ($(B).hasClass('right')) {
// do something
}
else if ($(B).hasClass('wrong')) {
// do something
}
answered = "yes";
}
function waitForInput() {
// MOUSE CLICK
$(document).click(function() {
if (answered == "yes") {
answered = "no";
draw(0);
}
});
$('.answer').click(function(e) {
$('.answer').unbind('click');
if (answered == "no") {
calcTime(1);
e.stopPropagation();
if ($(this).hasClass('right')) {
// do something
}
else if ($(this).hasClass('wrong')) {
// do something
}
answered = "yes";
}
});
// KEYPRESSES
$(document).bind('keyup', function(e){
$(document).unbind('keyup');
if (answered == "yes") {
e.stopPropagation();
keyAns();
}
else if ( answered == "no") {
calcTime(1); // irrelevant
if(e.which == 81 || e.keyCode == 81) { // Q
AAA = '#ansQ';
e.stopPropagation();
keyNotAns(AAA);
}
else if(e.which == 87 || e.keyCode == 87) { // W
AAA = '#ansW';
e.stopPropagation();
keyNotAns(AAA);
}
else if(e.which == 69 || e.keyCode == 69) { // E
AAA = '#ansE';
e.stopPropagation();
keyNotAns(AAA);
}
else if(e.which == 82 || e.keyCode == 82) { // R
AAA = '#ansR';
e.stopPropagation();
keyNotAns(AAA);
}
else {
}
waitForInput();
}
});
}
Every time that there's a keypress event, you rebind everything.
This means that if you push 10 keys, you will have 10 onclick listeners. So when a user then clicks, the callback will run 10 times in a row.
The code that you posted doesn't include the original call to the waitForInput function, but you only need to call it once, so you can delete it from this code.
A quick introduction to jquery events:
When you bind, every time that event occurs (on the element you put it to), the callback function you provided will run.
Another tip is that in more recent versions of jQuery, there in an alternative to bind named one. It does the same, but it will only run the first time. Although in this situation, you don't need it.
Your problem is that inside your keybind, you're calling waitForInput.
Asynchronous programming takes some getting used to, but what the functions do inside waitForInput is set up event listeners, and any time the event happens, those listeners fire.
The problem you're seeing is that after handling an event, you're adding more event listeners, and next time the event fires, the listener will fire multiple times.
Simply take the waitForInput() line out of the function, and put it at the bottom of your code. Then it will run only once, and you'll be fine. (It wouldn't hurt to rename it to something like setupEventListeners, to avoid confusion.)
Found it!
All thanks to Scott Mermelstein and ColBeseder, both equally invaluable to my solution! Not only did they find the flaws, they made me understand how events and binds work. So thanks a million, you two!
Indeed:
binds were being stacked, therefore IF it fired, it would fire excessively, also;
the self-call of waitForinput() was indeed unneeded, however;
one e.stopPropagation() was also needed, to prevent the loop from working with wrong event-data, which lead the function to interpret it as the next answer and fire itself again.
Plus: due to laziness - I didn't feel like too much trial and error - I wanted to stay on the safe side, so I added all unbind()'s as first-thing when the function fires.
The result, which works flawlessly, for those who're interested:
function keyNotAns (A) {
B = $(A).children('.answer');
if ($(B).hasClass('right')) {
// do something
}
else if ($(B).hasClass('wrong')) {
// do something
}
answered = "yes";
}
function waitForInput() {
$(document).unbind('keyup');
$(document).unbind('click');
$('.answer').unbind('click');
// MOUSE CLICKS
$(document).click(function() {
if (answered == "yes") {
answered = "no";
draw(0);
}
});
$('.answer').click(function(e) {
if (answered == "no") {
calcTime(1);
if ($(this).hasClass('right')) {
// do something
}
else if ($(this).hasClass('wrong')) {
// do something
}
e.stopPropagation();
answered = "yes";
}
});
// KEYPRESSES
$(document).bind('keyup', function(e){
if (answered == "yes") {
answered="no";
draw(0);
}
else if (answered == "no") {
if(e.which == 81 || e.keyCode == 81) { // Q
keyNotAns('#ansQ');
}
else if(e.which == 87 || e.keyCode == 87) { // W
keyNotAns('#ansW');
}
else if(e.which == 69 || e.keyCode == 69) { // E
keyNotAns('#ansE');
}
else if(e.which == 82 || e.keyCode == 82) { // R
keyNotAns('#ansR');
}
}
});
}
There are two ways to find such bugs. The first one is using the debugger - which can be pretty tedious when you have loops.
The second approach is logging: Write a report / log of all the important actions that you can read later to find out why it failed at some point in the past.
Have a look at console.log() or a JavaScript logging framework.

Modifying HTML elements using jquery

I am trying to use jquery to add and remove a class from <li> elements according to a variable's value ( i ).
Here is a jsfiddle of what I have done so far http://jsfiddle.net/LX8yM/
Clicking the "+" increments i by 1 ( I have checked this with chrome's javascript console ).
One should be able to click "+" and the class .active should be removed from and added to the <li> elements accordingly.
...I can get the first <li> element to accept the class, that's all...
No need for if statements:
$(document).ready(function (){
$('#add').click(function (){
$('.numbers .active').removeClass('active').next().addClass('active');
});
});
jsfiddle
Do note that I added an 'active' class to first list item. You could always do this via JS if you do not have control over the markup.
Your if..else.. is hanging in document.ready. Wrap the increment inside a function and call it respectively.
Like
$(document).ready(function (){
//variable
var i = 1;
//if statments
function incre(i){ // wrap into a function and process it
if(i == 1){
$('#one').addClass('active');
$('#two').removeClass('active');
$('#three').removeClass('active');
}else if(i == 2){
$('#one').removeClass('active');
$('#two').addClass('active');
$('#three').removeClass('active');
}else if(i == 3){
$('#one').removeClass('active');
$('#two').removeClass('active');
$('#three').addClass('active');
}
}
//change i
$('#add').click(function (){
incre(i++); // pass it as a parameter
});
});
Working JSFiddle
This would be easier:
$(document).ready(function(){
var i = 0; // set the first value
$('#something').click(function(){
i++; // every click this gets one higher.
// First remove class, wherever it is:
$('.classname').removeClass('classname');
// Now add where you need it
if( i==1){
$('#one').addClass('classname');
} else if( i==2){
$('#two').addClass('classname');
} else if( i==3){
$('#three').addClass('classname');
}
}):
});
See this code. Initially you have to add class to one.
$(document).ready(function (){
//variable
var i = 1;
$('#one').addClass('active');
//if statments
//change i
$('#add').click(function (){
i++;
if(i == 1){
$('#one').addClass('active');
$('#two').removeClass('active');
$('#three').removeClass('active');
}else if(i == 2){
$('#one').removeClass('active');
$('#two').addClass('active');
$('#three').removeClass('active');
}else if(i == 3){
$('#one').removeClass('active');
$('#two').removeClass('active');
$('#three').addClass('active');
}
});
});
It's being called only once, not in the click event function. This edit of your fiddle works: http://jsfiddle.net/LX8yM/2/
put it in the
'$('#add').click(function (){}'

How to check all text boxes are empty before clicking calculate

Hi all im new to jscipt,,, well, programming in general to be honest, but learning slowly for personal use.
I seek guidence on how i could place all the textboxes(inputs) in my index file into a list container, loop through them to check if they are empty or not before clicking the calculate button. If they are empty then inform the user of which one is empty.
Also, is there a way of preventing users from entering text into the textboxes and numbers only.
Background: im creating a form that requires all fields to be populate with numbers(in hours), a graph will then be generated from those values.
ive placed the file in skydrive for folks to download with the link below.
Index file
I did try the following but this alerts me regardless of weather the texboxes are populate or not.
function checkInputsGenerateGraph()
{
if( $('#hutz-hoursInput').val() == ""||$('#hutz-weeksPerYearInput').val() == ""||$('#hutz-jobsPerWeekInput').val() == ""||$('#hutz-hourlyMachineRateInput').val() == ""||$('#hutz-maintneneceDowntimeInput').val() == ""||$('#hutz-scrapRateInput').val() == ""||$('#hutz-toolsPerJobInput').val() == ""||$('#hutz-timeToLoadToolInput').val() == ""||$('#hutz-timeToSetPartsInput').val() == "")
{
alert('One them is empty!!');
}
else
{
$("#hutz-graph").slideDown();
$("#hutz-lblImproveMyProcess").slideUp();
$("#hutz-hoursInput").slideUp();
$("#hutz-weeksPerYearInput").slideUp();
$("#hutz-jobsPerWeekInput").slideUp();
$("#hutz-ourlyMachineRateInput").slideUp();
$("#hutz-ntneneceDowntimeInput").slideUp();
$("#hutz-scrapRateInput").slideUp();
$("#hutz-toolsPerJobInput").slideUp();
$("#hutz-timeToLoadToolInput").slideUp();
$("#hutz-timeToSetPartsInput").slideUp();
$("#hutz-lblMachineDetails").slideUp();
$("#hutz-lblPartSetting").slideUp();
$("#hutzcurrencyPreferenceInput").slideUp();
createChart();
}
}
First off, give all the required elements a common class, for examples sake we'll call this required:
<input type="text" class="required" id="hutz-hoursInput" />
Then, when your checkInputsGenerateGraph() function is called, you can loop over the required elements and check them:
$('.required').each(function() {
if (this.value.length == 0) {
alert(this.id + ' is empty!');
}
});
You could also do something like the following to remove all non-digits from your inputs:
$('.required').change(function() {
this.value = this.value.replace(/[^\d]+/, '');
});
See it in action
Hope that points you in the right direction!
edit
Here's a complete example:-
function checkInputsGenerateGraph() {
var isValid = true;
$('.example').each(function() {
if (this.value.length == 0) {
alert(this.id + ' is empty!');
isValid = false;
}
});
if (isValid) {
alert('do calculations!');
}
}
So, loop over all of the elements first, and make sure they are all populated. If not, set isValid to false so that once the loop completes, the calculations are not performed.

Categories