For loop issue in FireFox - javascript

Im working on a script which removes the default values in form elements using Prototype and LightView. The scripts works fine in Safari, but not at all in FireFox (3.5.5).
This fires when a lightview is triggered.
document.observe('lightview:opened', function() {
if($('contact_form')) {
var defaults = new Array();
var ins = $('contact_form').getElements();
var inlen = ins.length;
for(i=0; i < inlen; i++) {
alert(i)
if($(ins[i]).readAttribute('type') != 'image') {
defaults[ins[i].name] = $(ins[i]).value;
$(ins[i]).observe('focus', checkDefault.bind(event, ins[i]));
}
}
function checkDefault(name, event) {
alert(name.name)
if($(name).value == defaults[name.name]) {
alert(defaults[name.name])
$(name).value = '';
}
}
}
});
The strange this is, when I check for the length of inlen the proper number is alerted, but when I alert 'i', only the first number is alerted. I can't figure out why this is happening.
Any ideas what's wrong here?
Here is the address of the problem:
http://bearing.krd-design.net/
Thanks
Rich

I'm not sure if this would cause that problem, but you are missing var:
for(var i=0; i < inlen; i++) {
Also, there are no semi-colon's after any of your alert()s.
Try correcting those, and see if it makes a difference.
EDIT:
As pointed out by Matt, in the comments: neglecting var creates the variable in the global scope. This could cause a problem if prototypejs also uses a global variable i (but I sincerely doubt that).
EDIT 2:
Another possibility is the array accessing by input name:
defaults[ins[i].name] = $(ins[i]).value;
Try declaring defaults as an object:
var defaults = {};

It sounds like a timing issue; the alerts slow execution to the point where your code works in FF. Do you use FireBug?

First of all, I think it is only going to i=0 is probably because the JS broke during the first iteration. To troubleshoot, I'd put alert() in between lines and see which line is breaking it.
My guess of the problem should be in the line:
$(ins[i]).observe('focus', checkDefault.bind(event, ins[i]));
The first parameter of the 'bind' function should be context and you are passing in 'event'. 'event' isn't defined and it should be the context or scope.
In your case, I think you can just use:
$(ins[i]).observe('focus', checkDefault(ins[i]));

Related

javascript use console.log without moving to new line

I am new to js and hope this is not too trivial, but I am unable to find any help on the net.
I wish to output to console.log and prevent moving to a new line, so the next time the output will be appended to the same line. ie,
"use strict";
for (let i = 0; i<=9;i++){
console.log(i); // here i would like to freeze the output so the result is 0123456789 on one line, rather than those digits in a column.
}
I have seen fixes involving assigning the outputs to a string and printing in 1 hit, but that seems incredibly crude. Even in Fortran 4 as I recall in the '70s, you could prevent moving to a new line before printing again, so I think I am missing something fundamental. Also I cannot find any general help on formatting numerical output in javascript. Can someone point me in the right direction?
Thanks
Unfortunately, the console.log() method will only write out a string to a single line and doesn't support the appending behavior you are looking for.
As you detailed in your original post, you could accomplish writing the final result out through the use of a variable (i.e. displaying the final concatenated string), but not continually appending to the same line within the console itself as the loop is being iterated over.
Alternative Grouping Option
The concept of grouping entries is supported, which is obviously very different than your original ask, but it may be worth considering as mentioned in the documentation for console.group() and might look something like this:
var rollingConcatenation = '';
console.group("Looping Group Example");
for (let i = 0; i<=9;i++){
rollingConcatenation += i;
console.log(rollingConcatenation);
}
console.groupEnd();
This can give your console the following appearance, which can help with readability (depending on your use cases):
Do It Yourself Implementation
Another option might be to store your current console value within a variable and at clear it and rewrite the updated values out. Depending on your very specific use cases, you could achieve the behavior you are looking for using something like this crude implementation:
// Define a custom console
var customConsole = {
// Store a reference to your backing value
tempValue: '',
// Always write out the most recent value
log: function(msg) {
this.tempValue += msg;
console.clear();
console.log(this.tempValue);
},
// A clear method to clear the backing console
clear: function() {
this.tempValue = '';
console.clear();
}
}
for (var i = 0; i < 10; i++) {
// Use your custom console instead of the normal one
customConsole.log(i);
}
Take a new variable outside the loop and then prepare that string inside the loop and then you can console.log() outside the loop.
var str = '';
for (let i = 0; i <= 9; i++) {
str += i;
}
console.log(str);

new Array(length) gives wrong size

Update: This bug affects v28 and was fixed for v29 onward.
Having a function like this:
function arrMany(len) {
var a = new Array(len);
}
If the function is called rapidly the length of the produced array sometimes has length of previous call to the function.
Expanding the function to:
function arrMany(len, show) {
var a = new Array(len);
if (show) {
someElementTextA.value = a.length;
someElementTextB.value = len;
}
}
And calling by e.g.:
function tick() {
arrMany(2);
arrMany(4);
arrMany(6);
arrMany(10, true);
}
setInerval(tick, 1000 / 200);
after a while someElementTextA shows the value 6 and not 10.
Sample fiddle edit
Sample fiddle show
When this happens, and one turn down fps to for example 1, it keeps spitting out wrong length for a long time.
The behavior typically manifests itself after about 20 seconds on my system.
Tested on: Firefox Linux i686; rv:28.0
Notes:
No action in Browser Console or Web Console.
If Web Console is open the error never occurs.
If Web Console is opened when the error manifests, it corrects itself at once.
Given pt. 3. it is rather hard to debug in a sane way using the browser itself.
Any good fix to this?
Update 1:
Have tested this on Firefox, Chrome and Opera. Firefox is the only browser that manifests the bug. No action in console.
From comments and answer: Does not manifest on Window XP, Firefox v31. Does manifest on #jdigital's system – i.e. it's not local to my system.
Update 2:
Always specifying show in above code does not make any difference.
function tick() {
arrMany(2, false);
arrMany(4, false);
arrMany(6, false);
arrMany(10, true);
}
Nor does using default parameter. But another point being that show is only for the convenience of the sample code.
As to solution for conundrum saying:
if (arr.length !== len) { arr = new Array(len); }
seems to work. But not sure if is is a fix, or if this can break the same way. Using
if (arr.length !== len) { arr = new Array(len); retry = 1; }
show that retry is done quite frequent.
Another fix, (as in debug testing); but in another way. By adding this inside the function, the array is always of correct length. As in: retry is always 0.
for (retry = 0; arr.length !== len && retry < 10; ++retry) {
arr = new Array(len);
}
As to question.
Question is more if there is any good fix to the bug, not if it is a bug or not.
Any information for why this is happening and if there is any similar code, e.g. not handling Arrays, that can break in the same way is also interesting, but was not part of the original question as such.
Update 3:
For, "what I am trying to do", it is a question about it in the general sense, not specific to a case.
It is not a syntax I usually use, but happens from time to time, usually in some debug or verbose output where using a sparse array is simpler then a loop. But it is then nice to know that it is not reliable.
At the same time I recognize others might have different needs and as such solutions to it, in the broad general sense, is always nice to have.
Then again; tipping it the other way around I guess it would be another argument against ever using it ... ;)
This worked for me:
function arrMany(w, show) {
(function () {
var a = new Array(w);
if (show) {
arw1.value = a.length;
arw2.value = w;
}
})();
}
Interesting read: JavaScript's Strange Threaded Nature
This code explores the following property:
(function() { new Object(); })(); is garbage collected properly
It looks like a bug in Firefox. This problem does not occur in Chrome etc.
When I add a logging statement:
function arrMany(w, show) {
var a = new Array(w);
if (show) {
if( a.length != w ) {
console.log(a);
}
arw1.value = a.length;
arw2.value = w;
}
}
When I run this, I can see that console.log is occasionally triggered, and the Firefox Web Console window shows that the array has 5 elements.
If I understand correctly, you want a workaround for this bug, even if it is an ugly hack, as long as it is reliable. If so, consider this approach, which explicitly initializes the array:
function arrMany(w, show) {
// should be:
// var a = new Array(w);
// but there's a bug in Firefox, see StackOverflow 22726716
//
var a = [];
for( var i = 0; i < w; i++ ) a[i] = undefined;
if (show) {
arw1.value = a.length;
arw2.value = w;
}
}

Why the eval() is not working with array

What's wrong with this code? Can anyone help out?
var read=new Array("i=10","j=20","k=i*j");
for(var i=0;i<read.length;i++)
{
alert(eval(read[i]));
}
Expecting output:
alert three times with values 10,20,200.
But actual output:
But alert Once with value 10.
When the loop executes the first time, you are setting i = 10, with eval. So the loop breaks out immediately.
So, you might want to change the loop variable to something else, like this
var read = new Array("i=10","j=20","k=i*j");
for(var idx=0; idx < read.length; idx++)
{
console.log(eval(read[idx]));
}
Output
10
20
200
Note: Please make sure that you read this question and the answers to that question, before using eval in your code.
Try this code
var read=new Array("i=10","j=20","k=i*j");
for(var index=0;index<read.length;index++)
{
alert(eval(read[index]));
}
while the loop is executing, at the first execution of i=10 the i variable is set to 10; so loop will be terminated because of the condition i<read.length (here... 10<3) remains false.
see the eval() tutorial.

Javascript: TypeError variable is undefined

I am currently building a small web application with similar functionality across all modules. I want to code small generic functions so that all programmers next to me, call these functions and these functions return necessary but important data for them to implement their functionality. In this example, I am trying to deal with the typical "choose true or false" exercise. So from the template.php they call this function:
function checkAnswers(){
var radiobuttons = document.form1.exer1;
var correctAnswers = answers(); //this is an array of string
var checkedAnswers = checkExerciseRB(radiobuttons, 2, correctAnswers);
for(i=0; i<checkedAnswers.length; i++){
alert(checkedAnswers[i]);
}
}
Function checkExerciseRB is my generic function, it is called from checkAnswers.
function checkExerciseRB(rbuttons, opciones, correct){
var answers = new Array();
var control = 0;
for(i=0; i<rbuttons.length; i++){
var noPick="true";
for(j=0; j<opciones; j++){
if(rbuttons[control+j].checked){
if(rbuttons[control+j].value==correct[i]){
answers[i]= 1;
noPick="false";
break;
}
else{
answers[i]=2;
noPick="false";
break;
}
}
}
if(noPick=="true")
answers[i]=0;
control=control+opciones;
}
return answers;
}
It works great but while looking at my favorite browsers (FireFox, Chrome) error log it says:
TypeError: rbuttons[control + j] is undefined
Any clue on how to deal with this matter?
This probably means that control + j is greater than or equal to the length of the array rbuttons. There's no such array element as rbuttons[control + j].
You should learn how to use the JavaScript debugger in your favorite browsers! Debuggers are great. They let you watch this code run, line by line, as fast or as slow as you want, and watch how the value of control changes as you go.
You’ll watch it, and you’ll think “Oh! That line of code is wrong!”
You're looping through rbuttons.length times, but in each loop you're adding 2 to control. Using control to index your array, you're going to run past the end.
Does the index specified by control + j exist in the array? i.e: If that evaluates to 4, is there at least 5 items in the array?
Also, you should be using var i, var j, etc inside your for loop. Without it your variables are leaking into the scope this code is executed in (most likely the global scope, and that's not good) :)

JavaScript & string length: why is this simple function slow as hell?

i'm implementing a charcounter in the UI, so a user can see how many characters are left for input.
To count, i use this simple function:
function typerCount(source, layerID)
{
outPanel = GetElementByID(layerID);
outPanel.innerHTML = source.value.length.toString();
}
source contains the field which values we want to meassure
layerID contains the element ID of the object we want to put the result in (a span or div)
outPanel is just a temporary var
If i activate this function, while typing the machine really slows down and i can see that FF is using one core at 100%. you can't write fluently because it hangs after each block of few letters.
The problem, it seems, may be the value.length() function call in the second line?
Regards
I can't tell you why it's that slow, there's just not enough code in your example to determine that. If you want to count characters in a textarea and limit input to n characters, check this jsfiddle. It's fast enough to type without obstruction.
It could be having problems with outPanel. Every time you call that function, it will look up that DOM node. If you are targeting the same DOM node, that's very expensive for the browser if it's doing that every single time you type a character.
Also, this is too verbose:
source.value.length.toString();
This is sufficient:
source.value.length;
JavaScript is dynamic. It doesn't need the conversion to a string.
I doubt your problem is with the use of innerHTML or getElementById().
I would try to isolate the problem by removing parts of the function and seeing how the cpu is used. For instance, try it all these ways:
var len;
function typerCount(source, layerID)
{
len = source.value.length;
}
function typerCount(source, layerID)
{
len = source.value.length.toString();
}
function typerCount(source, layerID)
{
outPanel = GetElementByID(layerID);
outPanel.innerHTML = "test";
}
As artyom.stv mentioned in the comments, cache the result of your GetElementByID call. Also, as a side note, what is GetElementByID doing? Is it doing anything else other than calling document.getElementById?
How would you cache this you say?
var outPanelsById = {};
function getOutPanelById(id) {
var panel = outPanelsById[id];
if (!panel) {
panel = document.getElementById(id);
outPanelsById[id] = panel;
}
return panel;
};
function typerCount(source, layerId) {
var panel = getOutPanelById(layerId);
panel.innerHTML = source.value.length.toString();
};
I'm thinking there has to be something else going on though, as even getElementById calls are extremely fast in FF.
Also, what is "source"? Is it a DOMElement? Or is it something else?

Categories

Resources