Javascript event not defined in Firefox - javascript

This has been asked before but I'm still struggling to wrap my head around how to fix the error in my case. I'm new to learning Javascript/jQuery. Firefox gives an error "ReferenceError: getFirstArr is not defined". I have a simplified script of what I'm trying to do here JSFiddle (to make it work, select a year button first before a month button).
The culprit seems to be the getFirstArr(videos[i]) line 28. I really don't even know what to try since my code seems correct. It works in Safari, Chrome and IE. Firefox is the odd man out. Here's a snippet of the on click event where the problem is.
$('.campbutton').on('click', function () {
camp = $(this).attr('id');
$('.campbutton').removeClass('green');
$(this).addClass('green');
$('#searcharea').html('<table></table>');
var campyear = camp + year;
var count = 1;
var noResultCount = 0;
for (i = 0; i < videos.length; i++) {
for (j = 0; j < 5; j++) {
getFirstArr(videos[i]); // Firefox doesn't like this line
function getFirstArr(video) { // prints the the array where a match is found
The JSFiddle will have the whole code. So my question is, why is Firefox not accepting the function call, and what needs to be changed? Any help or hints are appreciated (btw, I'm still working on getting the correct table tags to format the output correctly so the videos don't just stack on top of themselves).
Edit: The specific problem Firefox has is when the camp button is clicked, no videos load in the div. The other button events are fine.
Here's the entire code in question:
var videos = [ ["string1A", "string1B", "string1C"], ["string2A", "String2B", String2C"] ];
var camp = "";
var year = "";
$('#searcharea').html('select a year button first');
$('.yearbutton').on('click', function () {
year = $(this).attr('id');
$('.yearbutton').removeClass('green');
$(this).addClass('green');
});
$('.campbutton').on('click', function () {
camp = $(this).attr('id');
$('.campbutton').removeClass('green');
$(this).addClass('green');
$('#searcharea').html('<table></table>');
var campyear = camp + year;
var count = 1;
var noResultCount = 0;
for (i = 0; i < videos.length; i++) {
for (j = 0; j < 5; j++) {
getFirstArr(videos[i]);
function getFirstArr(video) {
if (campyear === video[j]) {
var pos = video.indexOf(video[j]);
$('#searcharea').append('<tr><td>' + video[(pos - pos)] + '</td>' + '<td>' + 'Composer: ' + video[(pos -pos) + 1] + '<br>' + 'Player: ' + video[(pos - pos) + 2] + '<br>' + 'Piece: ' + video[(pos - pos) + 3] + '</td>');
}
else noResultCount++;
if (campyear === video[j] && count % 3 === 0 && j === 4)
$('#searcharea').append('</tr><tr>');
if (i === videos.lenght && j === 4)
$('#searcharea').append('</table>');
}
}
count++;
}
if (noResultCount === videos.length * 5)
$('#searcharea').html("No results found");
});

http://jsfiddle.net/3ncc5xdx/123/
Here i have moved your function to outside the loop like so, I think it works, unless I misunderstood what the issue is:
$('.campbutton').on('click', function () {
camp = $(this).attr('id');
$('.campbutton').removeClass('green');
$(this).addClass('green');
$('#searcharea').html('<table></table>');
var campyear = camp + year;
var count = 1;
var noResultCount = 0;
function getFirstArr(video) {
if (campyear === video[j]) {
var pos = video.indexOf(video[j]);
$('#searcharea').append('<tr><td>' + video[(pos - pos)] + '</td>' + '<td>' + 'Composer: ' + video[(pos -pos) + 1] + '<br>' + 'Player: ' + video[(pos - pos) + 2] + '<br>' + 'Piece: ' + video[(pos - pos) + 3] + '</td>');
}
else noResultCount++;
if (campyear === video[j] && count % 3 === 0 && j === 4)
$('#searcharea').append('</tr><tr>');
if (i === videos.lenght && j === 4)
$('#searcharea').append('</table>');
}
for (i = 0; i < videos.length; i++) {
for (j = 0; j < 5; j++) {
getFirstArr(videos[i]);
}
count++;
}
if (noResultCount === videos.length * 5)
$('#searcharea').html("No results found");
});
So the reason that it works is that the function is now declared before it is used once. Also, its now only declared once rather than again and again in your loop. It probably works in Chrome because Chrome is pretty smart and figuring our what you were implying – but Firefox will need a slightly more strict approach.

Related

"for" in wrong loop .js

I'm having some problem with this function. I ask sorry if the code looks a bit confused.
Basically what i'm trying to do is to divide some elements between the top and bottom of the documents having between them the same space circa.
i wrote this code but seems like the first "for" cycle goes loop ever and ever again.
** update**
so i improved the code and now the problem seems to be the variable "ifc"(if-counter). It suppose to increase by one every time that one of the if or else if is completed , but as you can see on the console it always remain 0 .
anyone can help?
thanks
var sizewidth = window.innerWidth;
var sizeheight = 3000;
function initialPosition(){
var els = document.querySelectorAll('.ico');
var tb = Math.round(els.length * 0.4);
console.log(tb);
var lr = els.length - tb;
var distPixEachTopBottom = sizewidth / (tb/2);
console.log(distPixEachTopBottom);
var distPixEachLefRight = sizeheight / (lr/2);
var nextTop = 0;
var nextLeft = 0;
var nextBottom = 0;
var nextRight = 0 ;
for (i = 0; i < els.length; i++) {
var ifc = 0;
console.log('i' + i);
if(i < tb){
var sf = 0;
for(;;){
console.log('sf' + sf + 'tb ' + tb);
if(ifc > 1){
console.log('ifc'+ ifc);
ifc = 0;
break
}else if(ifc == 0){
els[i].style.top = 0 +'px';
els[i].style.left = nextTop + 'px';
console.log('ifc ' + ifc + 'i ' + i + 'nexttop' + nextTop)
nextTop = nextTop + distPixEachTopBottom;
ifc++;
break;
}else if(ifc == 1){
els[i].style.bottom = 0 +'px';
els[i].style.right = nextBottom + 'px';
console.log('ifc ' + ifc + 'i ' + i + 'nextbottom' + nextBottom)
nextBottom = nextBottom + distPixEachTopBottom;
ifc++;
break;
}else{
console.log('else if problem')
break;
}
}
}else{
}
}
initialPosition();
update
i created a pen as you asked
codepen
So basically of all the boxes the 40% of them (6 in this case) should be divided between top and bottom but they go just on top.
So I solved by myself .
I put the var ifc before then any function .
Anyway thanks everyone

Array issue when the length is below 5

Listing last five items in an array by using this code below worked so far, but when the array length was only 1 it started causing issues. Can I some how condition it so it doesn't cycle though when there is only one item in the array?
$(function() {
$.getJSON("#myURL", function(getStressTestErrorInfo2) {
if (getStressTestErrorInfo2.length >= 1) {
var len = getStressTestErrorInfo2.length - 5;
var data = getStressTestErrorInfo2;
var txt = "";
if (data.length - 1 !== undefined) {
for (var i = len; i < len + 5; i++) {
// dynamically generating a table-row for appending in the table.
txt += "<tr><td>" + data[i].AlarmNo + "</td><td>" + data[i].AlarmCnt + "</td><td>" + data[i].StresstestId + "</td><td>" + data[i].StresstestRunId + "</td><td>" + data[i].Name + "</td><td>" + data[i].StackTrace + "</td><td>" + data[i].Timestamp + "</td></tr>";
}
if (txt != "") {
// #table is the selector for the table element in the html
$("#listErrorsTest2").append(txt);
}
}
};
});
});
Change this line:
if (getStressTestErrorInfo2.length >= 1) {
to:
if (getStressTestErrorInfo2.length >= 5) {
This way, it wont start the function, if the length is lower then 5.
The issues you have is that no matter the size of the array, you take the size and substract 5 to it. Allowing you to take the last 5 cells of an array ... long enough. If the length is below 5, the index will be negative.
Now, you can't simply update the condition if you want to get the values of smaller arrays.
You can simply set the index to 0 if it is negative :
var len = getStressTestErrorInfo2.length - 5;
if (len < 0) len = 0; //Array with less than 5 values.
And loop until you reach the end
while(len < getStressTestErrorInfo2.length){ ... }
My approach at the begging had some (stupid) flaws. Instead of showing the last 5 items I reversed the array and listed first five and added the condition
if (len > 5) len = 5;
so it did the trick.
$(function() {
$.getJSON("#myURL", function(getStressTestErrorInfo0) {
if (getStressTestErrorInfo0.length >= 1) {
var data = getStressTestErrorInfo0;
/*Function to reverse the array*/
function reverseArr(input) {
var ret = new Array;
for (var i = input.length - 1; i >= 0; i--) {
ret.push(input[i]);
}
return ret;
}
var reverseData = reverseArr(data);
var len = getStressTestErrorInfo0.length;
var data = getStressTestErrorInfo0;
var txt = "";
if (len > 0) {
if (len > 5) len = 5;
for (var i = 0; i < len; i++) {
// dynamically generating a table-row for appending in the table.
txt += "<tr><td>" + reverseData[i].AlarmNo + "</td><td>" + reverseData[i].AlarmCnt + "</td><td>" + reverseData[i].StresstestId + "</td><td>" + reverseData[i].StresstestRunId + "</td><td>" + reverseData[i].Name + "</td><td>" + reverseData[i].StackTrace + "</td><td>" + reverseData[i].Timestamp + "</td></tr>";
}
if (txt != "") {
//selector for the table element in the html
$("#listErrors").append(txt);
}
}
};
});
});

Adding an onclick event to a new html element only working on the last element

The problem is that when I create page number buttons at the bottom of the page the onclick only ever works with the last element created.
Here is what the page buttons look like:
for(var i = 0; i < numberOfPages; i++) {
if(Math.floor((((startIndex + 1) / 10) + 1)) == (i + 1)) {
var newElement = document.createElement("u");
document.getElementById("imagesNav").appendChild(newElement);
newElement.id = "imagesNavU";
var newElement = document.createElement("a");
document.getElementById("imagesNavU").appendChild(newElement);
var str = "page" + (i + 1);
newElement.innerHTML = i + 1;
newElement.onclick=function(){currentPageNumber(str);};
} else {
var newElement = document.createElement("a");
document.getElementById("imagesNav").appendChild(newElement);
var str = "page" + (i + 1);
newElement.innerHTML = i + 1;
newElement.onclick=function(){currentPageNumber(str);};
}
if(i + 1 != numberOfPages) {
document.getElementById("imagesNav").innerHTML += " ";
}
}
}
The first if statement just puts underline tags on if that element is the current page.
Edit: The problem has been solved. Thank you to everyone for their help!
The problem is with this part of the loop:
if(i + 1 != numberOfPages) {
document.getElementById("imagesNav").innerHTML += " ";
}
This is re-parsing all the HTML in the imagesNav element. This creates new <a> elements, which don't have the onclick bindings that the previous ones had.
Instead, you can append a <span> element containing the spaces.
var numberOfPages = 3;
var startIndex = 0;
for (var i = 0; i < numberOfPages; i++) {
if (Math.floor((((startIndex + 1) / 10) + 1)) == (i + 1)) {
var newElement = document.createElement("u");
document.getElementById("imagesNav").appendChild(newElement);
newElement.id = "imagesNavU";
var newElement = document.createElement("a");
document.getElementById("imagesNavU").appendChild(newElement);
var str = "page" + (i + 1);
newElement.innerHTML = i + 1;
newElement.onclick = function() {
currentPageNumber(str);
};
} else {
var newElement = document.createElement("a");
document.getElementById("imagesNav").appendChild(newElement);
var str = "page" + (i + 1);
newElement.innerHTML = i + 1;
newElement.onclick = function() {
currentPageNumber(str);
};
}
if (i + 1 != numberOfPages) {
var span = document.createElement('span');
span.innerHTML = ' ';
document.getElementById("imagesNav").appendChild(span);
}
}
function currentPageNumber(str) {
alert(str);
}
<div id="imagesNav">
</div>
Another way to do it is with insertAdjacentHTML, which adds HTML to an element without re-parsing what's already in it.
document.getElementById("imagesNav").insertAdjacentHTML('beforeend', ' ');
You should also see JavaScript closure inside loops – simple practical example because the way you're using the str variable, all the click handlers will use the value from the last iteration of the loop.

After calling function I'm getting error saying undefined

In my table 1st column has a tags with href's and 3rd column has some text. So, I want to save all href's into an array where their respective 3rd column matches some string and use it for later purpose. I had tried the following code nothing seems wrong to me, can some one assist me with this.
function findimagelinks(){
var rows = jQuery(".sortable tr.even").length + jQuery(".sortable tr.odd").length;
var imglinks = [];
for (i=0; i<rows; i++){
var conditionvalue =jQuery(".sortable tr:eq(i+1) td:eq(3)").text();
if(conditionvalue == "some string"){
imglinks[i] = jQuery(".sortable tr:eq(i+1) td:eq(0) a").attr('href');
}
}
console.log(imglinks);
}
findimagelinks();
String concatenation is not right!
var conditionvalue = jQuery(".sortable tr:eq(" + (i + 1) + ") td:eq(3)").text();
// ------------------------------------------^
imglinks[i] = jQuery(".sortable tr:eq(" + (i + 1) + ") td:eq(0) a").attr('href');
// -----------------------------------^
Updated Snippet
function findimagelinks(){
var rows = jQuery(".sortable tr.even").length + jQuery(".sortable tr.odd").length;
var imglinks = [];
for (i = 0; i < rows; i++) {
var conditionvalue = jQuery(".sortable tr:eq(" + (i + 1) + ") td:eq(3)").text();
if (conditionvalue == "some string") {
imglinks[i] = jQuery(".sortable tr:eq(" + (i + 1) + ") td:eq(0) a").attr('href');
}
}
console.log(imglinks);
}
findimagelinks();
Your selector is wrong. Properly concatenate the strings like this
var conditionvalue = jQuery(".sortable tr:eq(" + (i + 1) + ") td:eq(3)").text();
Then your code will look like,
for (i = 0; i < rows; i++) {
var conditionvalue = jQuery(".sortable tr:eq(" + (i + 1) + ") td:eq(3)").text();
if (conditionvalue == "some string") {
imglinks[i] = jQuery(".sortable tr:eq(" + (i + 1) + ") td:eq(0) a").attr('href');
}
}

Javascript function - works in IE, not in chrome

To preface this, we are a small organization and this system was built by someone long ago. I am a total novice at javascript so I have trouble doing complicated things, but I will do my best to understand your answers. But unfortunately redoing everything from scratch is not really an option at this point.
We have a system of collecting data where clients use a login to verify a member ID, which the system then uses to pull records from an MS Access database to .ASP/html forms so clients can update their data. One of these pages has the following function that runs on form submit to check that data in fields a/b/c sum to the same total as d/e/f/g/h/i. It does this separately for each column displayed (each column is a record in the database, each a/b/c/d/e/f is a field in the record.)
The problem is with this section of the function:
for (var j=0; j<recCnt; j++) {
sumByType = milesSurf[j] + milesElev[j] + milesUnder[j];
sumByTrack = milesSingle[j] + milesDouble[j] + milesTriple[j] + milesQuad[j] + milesPent[j] + milesSex[j];
etc.
It should use javascript FOR to loop through each record and test to see if they sum to the same thing.
In Firefox and IE this is working properly; the fields sum properly into "sumByType" and "sumByTrack". You can see below I added a little alert to figure out what was going wrong:
alert(sumByType + " " + j + " " + recCnt + " " + milesSurf[j] + " " + milesElev[j] + " " + milesUnder[j]);
In Chrome, that alert tells me that the components of "sumByType" and "sumByTrack" (the various "milesXXXXX" variables) are undefined.
My question is: Why in Chrome is this not working properly, when in IE and FFox it is? Any ideas?
Full function code below:
function submitCheck(formy, recCnt) {
//2/10/03: added milesQuad
//---------------checks Q#4 that Line Mileage by type is the same as by track
var milesElev = new Array();
var milesSurf = new Array();
var milesUnder = new Array();
var milesSingle = new Array();
var milesDouble = new Array();
var milesTriple = new Array();
var milesQuad = new Array();
var milesPent = new Array();
var milesSex = new Array();
var sumByType = 0;
var milesLineTrack = new Array(); //this is for Q5 to compare it to mileage by trackage
var j = 0; var sumByTrack = 0; var liney; var yrOp;
//var str = "document.frm.milesElev" + j;
//alert(str.value);
for (var i in document.frm) {
if (i.substring(0, i.length - 1) == "milesElev") {
milesElev[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length - 1) == "milesSurf") {
milesSurf[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length - 1) == "milesUnder") {
milesUnder[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length - 1) == "milesSingle") {
milesSingle[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length - 1) == "milesDouble") {
milesDouble[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length - 1) == "milesTriple") {
milesTriple[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length - 1) == "milesQuad") {
milesQuad[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length - 1) == "milesPent") {
milesPent[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length - 1) == "milesSex") {
milesSex[parseInt(i.substring(i.length-1, i.length))] = parseFloat(document.frm[i].value); }
if (i.substring(0, i.length -1) == "milesLineTrack") {
milesLineTrack[parseInt(i.substring(i.length-1, i.length))] = document.frm[i].value; } //12/13/02 used to be parseFloat(document.frm[i].value)
if (i.substring(0,5)=="Lines") {
liney = document.frm[i].value;
if (parseInt(liney)<1 || isNaN(liney)) {
alert("Each mode must have at least 1 line. Please correct the value in question #2.");
document.frm[i].select(); return false; }}
if (i.substring(0,8)=="yearOpen") {
yrOp = document.frm[i].value;
if (parseInt(yrOp)<1825 || isNaN(yrOp)) {
alert("Please enter a year after 1825 for question #3");
document.frm[i].select(); return false; }
}
}
for (var j=0; j<recCnt; j++) {
sumByType = milesSurf[j] + milesElev[j] + milesUnder[j];
sumByTrack = milesSingle[j] + milesDouble[j] + milesTriple[j] + milesQuad[j] + milesPent[j] + milesSex[j];
//---------------to round sumByTrack and sumByType from a long decimal to a single decimal place, like frm 7.89999998 to 7.9.
sumByTrack = sumByTrack * 10;
if (sumByTrack != parseInt(sumByTrack)) {
if (sumByTrack - parseInt(sumByTrack) >= .5) {
//round up
sumByTrack = parseInt(sumByTrack) + 1; }
else { //truncate
sumByTrack = parseInt(sumByTrack); }}
sumByTrack = sumByTrack / 10;
sumByType = sumByType * 10;
if (sumByType != parseInt(sumByType)) {
if (sumByType - parseInt(sumByType) >= .5) {
//round up
sumByType = parseInt(sumByType) + 1; }
else { //truncate
sumByType = parseInt(sumByType); }}
sumByType = sumByType / 10;
//-------------end of rounding ---------------------------
if (sumByType != sumByTrack) {
if (isNaN(sumByType)) {
sumByType = "(sum of 4.a., b., and c.) "; }
else {
sumByType = "of " + sumByType; }
if (isNaN(sumByTrack)) {
sumByTrack = "(sum of 4.d., e., f., g., h., and i.) "; }
else {
sumByTrack = "of " + sumByTrack; }
alert("For #4, the 'End-to-End Mileage By Type' " + sumByType + " must equal the 'End-to-end Mileage By Trackage' " + sumByTrack + ".");
alert(sumByType + " " + j + " " + recCnt + " " + milesSurf[j] + " " + milesElev[j] + " " + milesUnder[j]);
return false;
}
//alert (milesLineTrack[j] + " " + milesSingle[j] + " " + 2*milesDouble[j] + " " + 3*milesTriple[j] + " " + 4*milesQuad[j] + " " + 5*milesPent[j] + " " + 6*milesSex[j]);
var singDoubTrip = (milesSingle[j] + 2*milesDouble[j] + 3*milesTriple[j] + 4*milesQuad[j] + 5*milesPent[j] + 6*milesSex[j])
//----------round singDoubTrip to one digit after the decimal point (like from 6.000000001 to 6.0)
singDoubTrip = singDoubTrip * 10;
if (singDoubTrip != parseInt(singDoubTrip)) {
if (singDoubTrip - parseInt(singDoubTrip) >= .5) {
//round up
singDoubTrip = parseInt(singDoubTrip) + 1; }
else { //truncate
singDoubTrip = parseInt(singDoubTrip); }}
singDoubTrip = singDoubTrip / 10;
//----------end round singDoubTrip-----------------------------------------
if (parseFloat(milesLineTrack[j]) != singDoubTrip) {
//var mlt = milesLineTrack[j];
//if isNaN(milesLineTrack[j]) { mlt =
alert("For column #" + (j+1) + ", the mainline passenger track mileage of " + milesLineTrack[j] + " must equal the single track plus 2 times the double track plus 3 times the triple track plus 4 times the quadruple track plus 5 times the quintuple track plus 6 times the sextuple track, which is " + singDoubTrip + ".");
return false;
}
}
//---------------------end of checking Q#4----------------
//return false;
}
I think for (var i in document.frm) is the problem. You should not enumerate a form element, there will be plenty of unexpected properties - see Why is using "for...in" with array iteration a bad idea?, which is especially true for array-like objects. I can't believe this works properly in FF :-)
Use this:
var ele = document.frm.elements; // or even better document.getElementById("frm")
for (var i=0; i<ele.length; i++) {
// use ele[i] to access the element,
// and ele[i].name instead of i where you need the name
}
Also, you should favour a loop over those gazillion of if-statements.

Categories