Strange results with javascript array.length function - javascript

I have piece of JavaScript code which cycles through form elements and builds an object.
I have a mixture of HTML input fields and ASP.NET input fields. ASP.NET changes the ID of the fields to the form xxxxx_yyyy_id, so I am attempting to use the split function to extract the original id.
// Iterate over all the text fields and build an object
$(':text').each(function () {
var tokens = this.id.split("_");
if (tokens.length = 3) {
// Assume this is a .net inputbox - extract the original id
inFormData[tokens[2]] = this.value;
} else {
inFormData[this.id] = this.value;
}
});
Stepping through the above code, the first id is ctl00_ContentPlaceHolderCol1_forenameField, so the tokens.length = 3 code is run.
On the second iteration, the id is forenameField2 so I would expect the tokens.length to be 1, but it is actually 3. The else statement is never run.
This could be something simple, but I cant work it out. If I inspect the tokens array it has only 1 element in on the second iteration. I have also tried setting the array.length to 0 after each iteration.
Any help appreciated.

Correct this:
== instead of =. === is more better
if (tokens.length == 3) {
// Assume this is a .net inputbox - extract the original id
inFormData[tokens[2]] = this.value;
} else {
inFormData[this.id] = this.value;
}

Change your = 3 to === 3
At the moment you're overwriting tokens.length every time.
NB: === is preferred to == because it's an exact equality check. The two-equals version will attempt to cast the two operands to the same type before comparison, which is 1. unnecessary, 2. inefficient, 3. sometimes error prone.

That is why you should always put the constant first when testing. If you forget a comparison sign it will throw an error:
if( 3 = tokens.length ) // throws an error
if( 3 == tokens.length ) // ok
if( 3 === tokens.length) // ok

from:
if (tokens.length = 3) {
to:
if (tokens.length == 3) {

Related

Need help looping JSON with JavaScript. Weird behaviours

Although, it ran fine on small data. I need help looping through JSON in this form:
var current_value = 2;
json_data = {"2":"first information","3":"Second informaton","4":"Third information"}
What I want to do is get the value in the json_data that corresponds to current_value of 2
The problem is that I keep getting " anytime I run this loop:
for(x in json_data){
if(x === current_value){
extracted = json_data[current_value];
}
}
JavaScript property names are strings. 2 is a number. === does not do type conversion. "2" !== 2.
You should set current_value to "2" instead of 2.
The loop is pointless though.
A more sensible approach would be:
var extracted;
if (current_value in json_data) {
extracted = json_data[current_value];
}
… or even just skip the if statement. extracted will be undefined either way if the property doesn't exist.

JavaScript -- Validating a Certain Number of Inputs

I have 8 form inputs that are asking for either 8 half-day activity dates or, 4 fullday dates.
I collected all of the input values and put them into an array, and to test the collection process, wrote the following function that just says if ALL the inputs are empty, keep a button disabled and if ALL are full, enable the button.
function checkMeetings()
{
for(var i = 0; i < meetings.length; i++)
{
if(meetings[i] === "" || meetings[i] === null)
{
meetingsCanSubmit = false;
}
else
{
meetingsCanSubmit = true;
}
}
}
checkMeetings();
That test worked fine.
What I'd like to do is create a counter that counts the number of input boxes that have been filled in and when it gets to at >= 4 enable the button. (In reality it won't enable the button it's going to run a secondary function but for the purposes of this example I'm keeping it simple.)
Since the for loop is counting via the i++ anyways, I tried something to the effect of
if(meetings[i] <= 4) do the following, but that doesn't seem to be doing the trick. Should I be setting up a second counter within my if-statement?
You can use Array.prototype.filter(), check the .length of resulting array
var meetingsCanSubmit = meetings.filter(function(input) {
return input !== "" && input != null
}).length >= 4;
if (meetingsCanSubmit) {
// do stuff
}

String control in loops

I have a big question.
I have many Strings in my Programm and want to check these Strings on there values.
I wrote a Loop for it, but insted of the Definition of an String he is creating a new value. It's basicly really difficult to discribe, also because i am basicly German.
But i can give you my current code, so maybee you will see what I mean:
{
var Loch1G = $('#m1-Rundenanalyse-Datum').val(); //In the strings just the number is changing
var Loch2G = $('#m1-Rundenanalyse-Turnier').val();
x=1
while (x <= 2) {
if ("Loch" + x + "G" == ""){ //Next String is genrated (x=x+1)
alert("Eingabe war leer");
}
x=x+1
}
}
How can I solve this?
I'd suggest using an array to store the values you want to check:
var lochs = [];
lochs.push($('#m1-Rundenanalyse-Datum').val());
lochs.push($('#m1-Rundenanalyse-Turnier').val());
for (var i = 0, len = lochs.length; i < len; i++){
if (lochs[i] == ''){
alert("Eingabe war leer");
}
}
JS Fiddle demos: passes (no alert), fails (alert)
This suggestion is based on my presumption that you're trying to create the names of the vars you want to check, which won't work, whereas this approach lets you store all values (however many) in the same array and then iterate over that array to find any values that are equal to an empty string.
If you really want to stick with your current approach, you could do the following:
{
window.Loch1G = $('#m1-Rundenanalyse-Datum').val(); //In the strings just the number is changing
window.Loch2G = $('#m1-Rundenanalyse-Turnier').val();
var x=1;
while (x <= 2) {
if (window["Loch" + x + "G"] == ""){ //Next String is genrated (x=x+1)
alert("Eingabe war leer");
}
x=x+1;
}
}
But I can't think why you'd want to; plus the use of global variables is poor practice as it explicitly makes those variables available to every closure within the document, which allows them to be easily, and accidentally, overwritten.
In a reasonably up-to-date browser, that implements Array.prototype.every, you could dispense with the explicit iteration:
var lochs = [];
lochs.push($('#m1-Rundenanalyse-Datum').val());
lochs.push($('#m1-Rundenanalyse-Turnier').val());
if (!lochs.every(function(a){ return a !== ''; })) {
alert("Eingabe war leer");
}
JS Fiddle demos: passes (no alert), fails (alerts).

How to use IndexOf in JQuery

if($('#this').val().indexOf('4289')){
Do something
else
Do something.
This works only with that 4289,
When I try to add other numbers to be indexed next to it using 'or', it doesn't work. How should I put other number. E.g
IndexOf('4289||78843')
I want this to check this numbers and if the number in the input field is not one of this, to echo error.
Here's more which happens to die when one revisits the field.
$('#Zip').blur(function(){
if (($(this).val().indexOf('0860') > -1)||($(this).val().indexOf('0850') > -1)){
$('#Status_Zip').html("No way.")
$(this).alterClass('*_*', 'Success')
return false;
}else{$('#Status_Code').hide()
$(this).alterClass('*_*', 'Error')
$(this).css('border-color', '#F00').css('background-color', '#FFC').effect("pulsate",{times:4},2)
return true;
}
})
That's because it would be looking for the string '4289||78843', which doesn't exist in the target I'm assuming. Logical operators can't just be tossed in anywhere, only where there are actual values to logically operate on. Something like this:
if(($('#this').val().indexOf('4289') > -1) ||
($('#this').val().indexOf('78843') > -1))
The return value of the indexOf() function is the numeric index of that value in the target value, or -1 if it's not found. So for each value that you're looking for, you'd want to check if it's index is > -1 (which means it's found in the string). Take that whole condition and || it with another condition, and that's a logical operation.
Edit: Regarding your comment, if you want to abstract this into something a little cleaner and more generic you might extract it into its own function which iterates over a collection of strings and returns true if any of them are in the target string. Maybe something like this:
function isAnyValueIn(target, values) {
for (var i = 0; i < values.length; i++) {
if (target.indexOf(values[i]) > -1) {
return true;
}
}
return false;
}
There may even be a more elegant way to do that with .forEach() on the array, but this at least demonstrates the idea. Then elsewhere in the code you'd build the array of values and call the function:
var values = ['4289', '78843'];
var target = $('#this').val();
if (isAnyValueIn(target, values)) {
// At least one value is in the target string
}

JavaScript: Do I need a recursive function to solve this problem?

In this fiddle http://jsfiddle.net/5L8Q8/28/, if you click the black button, it randomly selects one of two values (red or blue) from an array. The randomly selected value is assigned to ran. In my real life application, there will be 16 elements in that array.
If you the pink "playagain" button, it chooses a random element from the same array but I want to make sure it's not the same one chosen as last time.
Therefore, when I click playagain, I assign ran to lastran and compare it to the next randomly chosen value from the array and, if they are the same, choose randomly again. However, the way I have it isn't guaranteeing that (upon the completion of playagain) ran is different.
I think I need a recursive function where comment 2 is in the code below, but I keep breaking my code when I try to create it.
Can you comment on the 3 comments in the code below?
Note, I'm a relative newbie, so this code is probably awful...
$("#playagain").click(function(){
lastran = ran;
ran = getRandom(myArray, true);
if (ran === lastran) {
ran = getRandom(myArray, true); //1. do I need to return this?
//2. want to test ran === lastran again.. How to set up recursive function?
} else {
return; //3.is this the right thing to do here?
}
});
while( (ran = getRandom(myArray, true)) === lastran)
;
Is what you want. The statement
ran = getRandom(myArray, true)
does not only set ran to getRandom(), but returns the value of ran. (This is a fairly common idiom in JavaScript, a carry over from C.)
So your full code can be:
$("#playagain").click(function(){
/*var */lastran = ran;
while( (ran = getRandom(myArray, true)) === lastran)
;
// update UI here
});
You can use a while loop instead of the if.
while(ran == lastran)
{
ran = getRandom(myArray, true);
}
It'll keep trying until it gets a different value.
After each run, simply remove that "key" from array and push lastran to the end of it. Then the updated getRandom function as following could be used both for #button and #playagain. http://jsfiddle.net/ghostoy/5L8Q8/32/
function getRandom(array, getVal) {
var key = Math.floor(Math.random() * array.length),
value = array[key];
if (lastran) {
array.push(lastran);
}
array.splice(key, 1);
lastran = value;
if (getVal) {
return value;
}
return key;
}
I think your approach is not the best way to deal with this. In theory you could get the same number many times in a row making this a 'slow' algorythm and you are making it more complex than needed.
An alternative approach in text:
- if no previous element has been picked pick a number between 0 and the number of elements in your array (16) otherwise pick a number between 0 and #elements-1 (15)
- if the chosen element is greater or equal to the last element picked add 1 to it
- store this index number as the last picked element
- return the array[picked-element]'s value
You could make getRandom itself recursive:
function getRandom(array, getVal, lastRan) {
var key = Math.floor(Math.random() * array.length);
if ((!getVal && key == lastRan) || (getVal && array[key] == lastRan))
return getRandom(array, getVal, lastRan);
return getVal ? array[key] : key;
}
Call it passing the last random value:
getRandom(myArray, true, lastran)
It works like this. You always pass getRandom the last random value that was retrieved. In the first conditional, we check to see if we just generated a duplicate of this value (either using the key itself or its corresponding value in the array, depending on whether getVal is true). If so, we return the result of calling getRandom again, once again passing the last random number that was used. This can happen as many times as necessary.
When one of these calls to getRandom produces a new number, then the expression in the first conditional will be false. In this case, we return the wanted value (via the second return statement) and all of the recursive calls to getRandom are "unrolled". (Remember, we returned the value of each call to getRandom at each step.)

Categories