Mysterious JavaScript behaviour.
November 24, 2005 7:09 AM   Subscribe

Mysterious JavaScript behaviour.

I have a webpage which contains 10 divs. Each div contains 10 questions. Each questions consists of 5 radio buttons. When the page is loaded the first div is shown and the other nine are hidden. None of the radiobuttons are marked by default.

I have put JavaScript validation in place which requires that all ten questions be answered before allowing a user to advance to the next set of questions i.e. display the next div. If they click the Next button and have not answered one or more questions then they are not shown the next set of questions and a span(s) next to the question(s) displays an 'Answer Required'. message.

It happened that a user was allowed to advance through the sets of questions without answering every question. I have logged the following details for this user and they are as follows :

Browser : IE
Browser Version : 6.0
Browser Supports Cookies : True
Browser Supports Javascript : True
Platform : Win2000

His details are the same as the machine on which the page was written and I have not been able to replicate the issue.

I will paste the code in anticipation of a request to do so, but I am not asking that the code be changed. I am asking why it is the case that JavaScript might work as intended on one machine and not on another very similar machine.

The code is called from a html buttons onclick event :

As I had asked a question in the previous week I posted the question on a Coding Forum, to no avail. You can read it if you wish but it will not help. The guy who responded never really addressed the question. Why would JavaScript work on one machine and not on another with the same OS and Browser.

Is it possible that a firewall would prevent some of the JavaScript but still allow the next set of questions to be displayed?


Sorry for the sprawling post. Ken.


var testPage = 1;
var totalTestPages = 11;
var questionNumber = 0;
var pageValid = 0;
var questionsPerPage = 10;
var questionValid = 0;
var pageValid = 0;


function NextTestPage()
{
//Initially assume that the page has been completed fully
pageValid = 1;

//Check sets of radio button on page
for (i = 1; i < questionsperpage; i++) { //calculate the current question number questionnumber=(((testPage * 10) - 10) + i); //assume that the question has not been answered fully questionvalid=0; //loop through each of the radio buttons for a question for (j=1 ; j =5; j++) { if (document.getelementsbyname ('answer' + questionnumber )[j - 1].checked=true) { //indicate that the question has been answered questionvalid=1; break; } } //if the question has not been answered then flag and highlight the validator if (questionvalid=0) { document.all(validator + questionnumber).innertext="Answer Required" ; pagevalid=0; } } //if the set of questions have all been answered then display the next set if (pagevalid=1) { for (i=1; i =totalTestPages; i++) { if (i=testPage) { document.getelementbyid('set' + i).style.visibility='visible'; } else { document.getelementbyid('set' + i).style.visibility='hidden'; } } //display the next question set testpage +=1; } } /code>
posted by kenaman to Computers & Internet (28 answers total)
 
Response by poster: As you can probably see the code is not displayed properly, though it was fine on preview. Its reposted below and I will flag it to get the code removed from the question if possible.


var testPage = 1;
var totalTestPages = 11;
var questionNumber = 0;
var pageValid = 0;
var questionsPerPage = 10;
var questionValid = 0;
var pageValid = 0;


function NextTestPage()
{
//Initially assume that the page has been completed fully
pageValid = 1;

//Check sets of radio button on page
for (i = 1; i < questionsperpage; i++)br> {
//Calculate the current question number
questionNumber = (((testPage * 10) - 10) + i);

//Assume that the question has not been answered fully
questionValid = 0;

//Loop through each of the radio buttons for a question
for (j = 1 ; j < 5; j++)br> {
if (document.getElementsByName ('answer' + questionNumber )[j - 1].checked == true)
{
//Indicate that the question has been answered
questionValid = 1;
break;
}
}

//if the question has not been answered then flag and highlight the validator
if (questionValid == 0)
{
document.all("validator" + questionNumber).innerText = "Answer Required";
pageValid = 0;
}
}


//If the Set of questions have all been answered then display the next set
if (pageValid == 1)
{
for (i = 1; i < totaltestpages; i++)br> {
if (i == testPage)
{
document.getElementById('set' + i).style.visibility='visible';
}
else
{
document.getElementById('set' + i).style.visibility='hidden';
}
}

//Display the next question set
testPage += 1;
}

}

posted by kenaman at 7:18 AM on November 24, 2005


This is maybe a silly answer, but could the user have javascript turned off (in IE advanced options)? I think that "Browser Supports Javascript : True" means the browser is capable of running javascript, but I doubt your log is actually testing if the user has javascript enabled. I expect your logging program sees that the user has IE6 (from HTTP headers), and is simply telling you that IE6 is JavaScript-capable.
posted by matthewr at 7:24 AM on November 24, 2005


that assumes the default is that the divs are invisible (it's not clear to me what the default is).
posted by andrew cooke at 7:34 AM on November 24, 2005


oh, sorry, i have it backwards. that makes more sense - they could see the questions, which is the likely default.

can you get the user to view a page that simply has javascript displaying "hello world"?
posted by andrew cooke at 7:35 AM on November 24, 2005


Response by poster: This is maybe a silly answer, but could the user have javascript turned off .... not all all. It was also suggested at the coding forum.

My reply there was that, while I do not check for JavaScript being enabled, were it disabled I think it would be impossible that the user be shown the next set of questions, as per the final for loop in the code.

Which lead to me asking the question 'Is it possible that a firewall would prevent some of the JavaScript but still allow the next set of questions to be displayed?'
posted by kenaman at 7:37 AM on November 24, 2005


Response by poster: can you get the user to view a page that simply has javascript displaying "hello world"?

I had them describe to me the output from the Script at this page

The response they got was :
Your browser supports JavaScript version 1.3.
posted by kenaman at 7:41 AM on November 24, 2005


a traditional firewall? they just block files. i suppose it's vaguely possible that you've hit an "intelligent" firewall that is changing messages in some way to block viruses, but that seems really unlikely to me. you'd have to get *really* unlucky for it to alter code to not crash, but do something unexpected.

so the css has these divs defined with display: none (or visibility: hidden)?

(i just checked that site with a browser with disabled javascript and it reports that it's disabled, as i guess you've also tried...)
posted by andrew cooke at 7:54 AM on November 24, 2005


Response by poster: so the css has these divs defined with display: none (or visibility: hidden)?

Nope they are all visible initially, here is a sample tag less < and>:

div id="set1" style="LEFT: 20px; POSITION: absolute; TOP: 130px; BACKGROUND-COLOR: #ffffff;"


NextTestPage() is called onload which displays the "set1" div and hides the others.
posted by kenaman at 8:04 AM on November 24, 2005


ok, i may not have understood, but that sounds to me like it could be that javascript is simply not working. then they would see all the questions.

i'm confused because i thought you were saying that javascript has to be working, but not working correctly (and in a very specific way, so that it enables the right questions anyway).

but it sounds to me like "any little thing" that is causing javascript to fail would give the user experience you have.
posted by andrew cooke at 8:28 AM on November 24, 2005


Response by poster: Sorry for causing confusion. I know its a big question and is not really specific.

This user can move between question sets, which requires the JavaScript, but are allowed to do so without replying to all questions, a requirement which is supposedly enforced by JavaScript.

MY confusion arises from this fact.
posted by kenaman at 8:41 AM on November 24, 2005


Can you view the page source of the failed page (i.e. on the users' machine)? I discovered that ZoneAlarm caused problems with my (previous) broadband modem config pages - but I only discovered this when I checked the source of the page that wouldn't work and saw something "added by ZoneAlarm"...
posted by Chunder at 9:02 AM on November 24, 2005


ah! ok, sorry.
posted by andrew cooke at 9:04 AM on November 24, 2005


also - bad day for me - despite what i said earlier, i've seen what chunder describes, too. it wasn't exactly a firewall but a pop-up blocker, in my case.
posted by andrew cooke at 9:07 AM on November 24, 2005


1 - Can you observe this behavour happening, i.e., get that user to re-run the query?

2 - Maybe the user hacked the page. They could have

a) run this url javascript:questionsPerPage = 0;

or

b) applied their own style sheet to set all elements visible on the page
posted by SNACKeR at 9:14 AM on November 24, 2005


Users can selectively block javascript using a variety of methods. For instance, Firefox allows selected bits of javascript to be turned off; Proxomitron (and Greasemonkey, etc.) can filter and transform javascript.

Your page uses css to set visibility; this can also be overridden a number of ways.

Take home message: you can't rely on javascript for form validation.
posted by orthogonality at 9:14 AM on November 24, 2005


I hope this is not derailing your question but it appears that you are relying on javascript as a security measure of some sort. That's not a good idea for anything serious. I can think of about 5 ways off the top of my head that I would be able to get around your method and answer all the questions in any order I please, all while still passing any kind of "make sure javascript is enabled" detection present.

So if you know that this user was being honest and not trying to cheat in any way then I can't help you with your question. If you're really asking, "Would it be possible for someone to subvert this if they wanted to" then the answer is a resounding yes. So in other words if this is for an online test for some kind of graded coursework, then you really are only keeping honest people honest -- anyone that wanted to cheat would have plenty of options.
posted by Rhomboid at 9:18 AM on November 24, 2005


(Heh well it looks like others already beat me to it while I was typing... ) Some of the methods include:

- a filtering proxy (such as proxomitron or privoxy) that modifies the code before it gets to the browser
- injecting your own javascript to modify the behavior: by typing it directly using a javascript: url, using venkman, using greasemonkey, etc.
- overriding the styles with a user stylesheet
- not even using a browser at all and posting the completed form with something like cURL with user-agent spoofed to that of a browser

the list goes on...
posted by Rhomboid at 9:25 AM on November 24, 2005


Response by poster: 1 - Can you observe this behavour happening, i.e., get that user to re-run the query?

I am going to get remote control of the offending machine tomorrow.

2 - Maybe the user hacked the page. They could have

The user was under direction human supervision at the time, so this is not the issue.

They were using IE 6.0 and had JavaScript 1.3 enabled.

I take all the points about relying on JavaScript for validation there is an amount of Server Side validation also.
posted by kenaman at 10:14 AM on November 24, 2005


I must say, I'm finding your JavaScript rather confusing -- this bit for instance:

questionNumber = (((testPage * 10) - 10) + i);

has the number ten hard-coded, not the variable 'questionsperpage'. Your 'questionsperpage' is set to ten, so it should work, but that's going to cause you lots of problems as soon as the number changes.

And you're going through a bit of a rigmarole just to get "page 1 contains questions 1 to 10, page 2 contains questions 11 to 20".

If the first page is page zero, then you can just do this:
questionNumber = (testPage * questionsPerPage) + i;
because ten times zero is zero, plus one is one. Ten times one (for the second page) is ten, plus one is eleven.

You can add one to the page numbers for display purposes if you think your testees will find a test from page 0 to 9 confusing.


This bit as well:

for (j = 1 ; j < 5; j++)br> {
if (document.getElementsByName ('answer' + questionNumber )[j - 1].checked == true)


why are you doing j-1, when you could have j start with zero, not one? And again, the 5 is hard-coded. There are always five answers per question?

These things aren't solving your problem, I know, but it looks like you could refactor the whole thing a bit.
posted by AmbroseChapel at 12:30 PM on November 24, 2005


After thinking about it,

* it's not possible for us to diagnose without the HTML as well, and
* what I do to debug javascript is put an alert() statement for every key part of the code, which will pop up and say "value of x is y, value of a is b, currently testing radio button foo of question bar" and so on. It's annoying but it's the only way, unless you've got a JavaScript programming environment to work in.
posted by AmbroseChapel at 2:02 PM on November 24, 2005


AmbroseChapel writes "unless you've got a JavaScript programming environment to work in."

Javascript debugger ("Venkman") extension in firefox.
posted by orthogonality at 2:10 PM on November 24, 2005


I don't know what the specific problem is here, but here's what you can do to find out when you have access to the computer with the problem:

1) Put all this stuff in different functions! That way, you can work methodically through the parts of the operation and test each unit for correct behavior. You don't have to make a class for something as small as this, but this big block'o'function thing is a relic.

2) Make a copy of the page with a div id called "debug", and write to it whenever anything important happens. You'll see exactly what is and isn't happening at each step in your new compartmentalized implementation, and the culprit will stick out immediately.

Here's a quick demo of what I'm talking about that should be virtually identical to yours except for the number of questions. It works fine in Firefox, Opera, and IE so I'm not able to give you any really specific advice.
posted by moift at 5:05 PM on November 24, 2005


Debugging alerts are the way to go. If this problem were occuring in Firefox it'd be a cinch to track down, thanks to the Javascript logger; IE6 has one too, I think, but its Javascript error messages are completely useless.

The script looks like it should work (though it seems a bit obtuse for some reason I can't figure out), but as stated before, if the user has Javascript disabled all your divs will be visible. If you really don't want the user to have access to a question before the previous one has been answered, either split the page up into several pages (one for each question) or use some AJAX magic along with server-side validation.
posted by chrominance at 5:14 PM on November 24, 2005


Could the Microsoft Script Debugger be used? (link)

I've never used it myself, but debugging HTML pages with scripts on them seems to be what it's for. The Microsoft IE Developer Toolbar (link) should be the solution to this whole problem, but for some reason it doesn't include a decent JavaScript debugger AFAICT.
posted by matthewr at 5:42 PM on November 24, 2005


Best answer: Yeah, it will be easier to debug if you break it up into logical functions (and pass variables you need into the functions rather than relying on JavaScript to find them globally). Also, assuming the page is valid to begin with might be part of the problem; I usually assume the worst about users (invalid) and then let them prove otherwise.

If you have a lot of debugging to do on the page, rather than clicking 42 alert boxes, add another div on the page with an id like "debug", position it out of the way and create a function called something like debug() that accepts a string-- let this function append the string to the .innerHTML property of the debugging div. I find that a less intrusive way to get information about what's going on. If you need more than that, the Venkman debugger is your answer.
posted by yerfatma at 5:49 PM on November 24, 2005


Response by poster: Thanks to all of you so much for all your effort.

2) Make a copy of the page with a div id called "debug", and write to it whenever anything important happens. You'll see exactly what is and isn't happening at each step in your new compartmentalized implementation, and the culprit will stick out immediately.


this looks like a great suggestion and also mofit thank you so much for that demo.

I will take on board all the refactoring sugestions and make changes accordingly. I just hope that I am able to replicate the issue today, when I get access to the machine. I'll let you know. Thanks again.
posted by kenaman at 1:26 AM on November 25, 2005


Response by poster: Not granted access to that machine. None the wiser will return to this thread if successful. In the mean time I am going implement mofits suggestion of the debug div to trap the events which occurred when/if the issue rears its head again.
posted by kenaman at 3:14 AM on November 28, 2005


Response by poster: Never did solve the problem. I took yerfatma's suggestion about the hidden debug div which logs every action the user has taken. Also any JavaScript errors will be caught and logged to this hidden div. The div can be shown/hidden by clicking on an hidden link and if the error occurs again the people overseeing the tests will know to send me the details from this div.
Thanks again all.
posted by kenaman at 2:12 AM on November 30, 2005


« Older How can I stop my rubbish bin stinking?   |   Help me put together the pieces... Newer »
This thread is closed to new comments.