Forum Moderators: open

Message Too Old, No Replies

Javascript form - check box problem

Javascript form - check box problem

         

haryanto

3:32 am on Feb 5, 2005 (gmt 0)

10+ Year Member



Hi guys,

I am having a small problem here.
I have a pretty nice script. At least I think so.
But the problem is that I need to get it working perfectly.

Here is what happens.
When I click on a checkbox, the row color changes.....neat....
:D

Then I have a check box at the top to toggle all the checkboxes. When I click on it, all the checkboxes on taht pages are checked.....neat....
:D

BUT......when I use the 'toggle all' checkbox, the background color didn't change...
;(
That makes me very grouchy....can someone make my day by providing a fix pls?


<script type="text/javascript" language="JavaScript">
function getParent(el) {
if (document.all)
while (el.parentElement!= null)
if (el.tagName == 'TR') return el;
else el = el.parentElement;
else if (document.getElementById) {
if (el.nodeType == 1 && el.tagName.toLowerCase() == 'tr') return el;
else return getParent(el.parentNode);
}
}

function setParentTR(e, CSSattr, CSSvalue) {
var el = (e && e.srcElement)? e.srcElement : (e && e.target)? e.target : null;
if (el) {
var which = el.checked;
var parentTR = getParent(el);
parentTR.style[CSSattr] = (which)? CSSvalue : '';
}
}

</script>
<script type="text/javascript" language="JavaScript">

var global=1;
function checkAll(formId, cName, check )
{
if(check==1)
{
for (i=0,n=formId.elements.length;i<n;i++)
if (formId.elements[i].className.indexOf(cName)!=-1)
formId.elements[i].checked = true;
}
if(check==0)
{
for (i=0,n=formId.elements.length;i<n;i++)
if (formId.elements[i].className.indexOf(cName)!=-1)
formId.elements[i].checked = false;
}

}
function toggle()
{
checkAll(document.getElementById('myform'), 'filecheck', global);
if (global==0)
{
global=1;
}
else if(global==1)
{
global=0;
}
}

</script>
<form id="myform"><table width="100%"><tr bgcolor="#CCCCCC" ><td><input type="checkbox" onclick="toggle();"></td>
<td>DATA</td>
<td align="left">DATA2</td><td>TIME</td></tr><tr bgcolor="#F1F1F1" ><td><input type="checkbox" class="filecheck" onclick="setParentTR(event,'background','#D9E9F8')"></td>
<td>DATA1</td><td align="left">DATA1</td><td>Feb 03 2005 (02:29)</td></tr><tr bgcolor="#FFFFFF" ><td><input type="checkbox" class="filecheck" onclick="setParentTR(event,'background','#D9E9F8')"></td>
<td>DATA2</td><td align="left">DATA2</td><td>Feb 03 2005 (03:11)</td></tr><tr bgcolor="#F1F1F1" ><td><input type="checkbox" class="filecheck" onclick="setParentTR(event,'background','#D9E9F8')"></td>
<td>DATA3</td><td align="left">DATA3</td><td>Feb 03 2005 (03:49)</td></tr></table>
</form>

haryanto

10:16 am on Feb 6, 2005 (gmt 0)

10+ Year Member



Nobody knows how to do it?

I think this must be a pretty tough one... :(

Thanks anyway...

Bernard Marx

3:09 pm on Feb 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



In the last year, two major websites have published articles related to this topic (row highlighting). IMHO both articles have flaws in their approach (I won't go into it).

The Bernard Marx solution, of course, is utter perfection.

The best tip is to make use of multiple classNames (appending & removing), rather than modifying each element's style properties directly. This gives greater flexibility, and gets round the problem of how to revert a row's style back to it's unselected state.

The striping of the odd rows (via className), and the event handlers could also be added with script, but I haven't done this.

(Unless I'm missing something) There is no need to pass the event object in a handler - and then query it for its source. It is easier to send the object itself, with the keyword,

[blue]this[/blue]
. The global 'state' variable is also not needed.

You had a function that got a reference to an element's parent row. I have changed this to

[blue]getAncestor[/blue]
. It is now more generic. Making it generic had required the use of regular expressions to cover the case were case should be ignored. Since we no longer need to call
[blue]toLowerCase[/blue]
on each value string, however, the efficiency is about the same.

The HTML has a few changes:

1. Removed:

bgcolor
attributes from rows.
2 Added: a stylesheet
3. Added:
[color=brown]class="odd"[/color]
to the odd (ie not even) rows.
4 Added:
[color=brown]id="files"[/color]
to table (for stylesheet application)
5. Changed: top checkbox event handler to
[color=brown]onclick="toggleAll(this);"[/color]

6. Changed: other checkbox event handlers to
[color=brown]onclick="setRow(this)"[/color]

-- HTML --

<html>
<head>
<title>checkboxes</title>
<script src="checkboxes.js" type="text/javascript"></script>
<style>
#files tr
{background-color: #F1F1F1;}
#files tr.head
{background-color: #CCCCCC;}
#files tr.odd
{background-color: #FFFFFF;}
#files tr.selected
{background-color: #D9E9F8;}

</style>
</head>
<body>
<form id="myform">
<table width="100%" id="files">
<tr class="head" >
<td><input type="checkbox" onclick="toggleAll(this);"></td>
<td>DATA</td>
<td align="left">DATA2</td>
<td>TIME</td>
</tr>
<tr>
<td><input type="checkbox" class="filecheck" onclick="setRow(this)"></td>
<td>DATA1</td>
<td align="left">DATA1</td>
<td>Feb 03 2005 (02:29)</td>
</tr>
<tr class="odd">
<td><input type="checkbox" class="filecheck" onclick="setRow(this)"></td>
<td>DATA2</td>
<td align="left">DATA2</td>
<td>Feb 03 2005 (03:11)</td>
</tr>
<tr>
<td><input type="checkbox" class="filecheck" onclick="setRow(this)"></td>
<td>DATA3</td>
<td align="left">DATA3</td>
<td>Feb 03 2005 (03:49)</td>
</tr>
</table>
</form>
</body>
</html>

-- Script (checkboxes.js) -- *! replace all instances of ¦ with an unbroken pipe character

[color=darkgreen]/* always handy */[/color]
String.prototype.trim = function(){ return this.replace(/^\s*¦\s*$/g,"")}

[color=darkgreen]/* Last arg optional - use 'i' or leave out. */[/color]
function getAncestor(elm,prop,val,ignCase)
{
if(val.constructor!= RegExp)
val = new RegExp('\\b'+val+'\\b', ignCase);
while(!(val.test(elm[prop])))
elm = elm.parentNode¦¦elm.parentElement; [color=darkgreen]/* only for IE4 (I think) */[/color]
return elm;
}

function setRow(box, select)
{
[color=darkgreen]/* Get fn reference to choose appropriate function,
then call function */[/color]
var classModifier = select? appendClass : removeClass;
classModifier( getAncestor(box,'tagName','tr','i'), 'selected');
row = getAncestor(box,'tagName','tr','i')
}

function toggleAll(togBox)
{
var boxes = togBox.form.elements;
var check = togBox.checked;
var box, i=0;
while(box=boxes[i++])
if(box.className == 'filecheck'){
box.checked = check;
setRow(box,check);
}
}

function appendClass(elm, appClass)
{
[color=darkgreen]/* only add space if currClass non-empty */[/color]
elm.className += (elm.className? ' ':'') + appClass;
}

function removeClass(elm, className)
{
[color=darkgreen]/* Replace className, and surrounding spaces, with a single space;
Trim end (since space may have been added to end) */[/color]
elm.className = elm.className
.replace(new RegExp('\s*'+className+'\s*'),' ')
.trim();
}

Bernard Marx

4:23 pm on Feb 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Bug correction:

function toggleAll(togBox)
{
var boxes = togBox.form.elements;
var check = togBox.checked;
var box, i=0;
while(box=boxes[i++])
if
(
box.className == 'filecheck'
[red]&& box.checked!=check[/red]
){
box.checked = check;
setRow(box,check);
}
}

haryanto

6:31 pm on Feb 6, 2005 (gmt 0)

10+ Year Member



The Bernard Marx method of doing it solves a problem and created another.

Yeah the rows are now highlighted when toggled-all but when checked individually, the row colors are not activated.

Great try by the way!

Bernard Marx

7:02 pm on Feb 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I don't know what you mean.
Everything works fine my end, and tested on IE & FF.

Rambo Tribble

7:42 pm on Feb 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Assuming that the example's relationships between the form elements and the table elements are consistent, how about a simple loop script like this one? (I didn't try to duplicate the check all function, which you already know how to do.)


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Untitled</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<style type="text/css">
td{border:2px solid blue;}
tr{background:#fee;}
</style>
<script type="text/javascript">
function rowYourBoat(){
var trs=document.getElementById('tableOne').rows;
for(var i=0;i<trs.length;i++){
if(document.frmOne.elements[i].checked){
trs[i].style.background="#eef";
}else{
trs[i].style.background="#fee";
}
}
}
</script>
</head>
<body>
<form action="" name="frmOne">
<table id="tableOne" onclick="rowYourBoat();">
<tr>
<td><input type="checkbox" /></td><td>data</td><td>data</td>
</tr>
<tr>
<td><input type="checkbox" /></td><td>data</td><td>data</td>
</tr>
<tr>
<td><input type="checkbox" /></td><td>data</td><td>data</td>
</tr>
<tr>
<td><input type="checkbox" /></td><td>data</td><td>data</td>
</tr>
</table>
</form>
</body>
</html>

Bernard Marx

8:46 pm on Feb 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



That's an interesting take, Rambo. Get shot of all those event handlers...and bubble.
I was sticking to the straight & narrow path of not making the "checkboxes correspond to rows" assumption, but it may not be necessary.

A little reworking would be req'd to account for the first row/checkbox having different behaviour. Not much though.

The original table is striped, so I'd still apply the striping via className, then change the ELSE branch in your function:

[color=brown]}else{ 
trs[i].style.background="";[/color]


to allow the original unselected styling to shine through.

I sometimes worry about response time - and was thinking of taking the bubbling further, so as not to do any looping - but I tried yours with a 200 row table, and there's less than 1/4 second delay even on row 200.

Rambo Tribble

9:01 pm on Feb 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Yes, the approach I've taken does depend on the relationships being consistent, but if they are it could be a simple solution. As for bubbling, well, we tribbles are noted for our effervescent personalities.

I have to admit, I've always been just the least bit uneasy about using the technique of resetting a property with property="". I realize it is a well-established browser convention, but it doesn't seem to be part of any kind of codified standard, so I sort of feel a nagging wisp of trepidation. Probably unfounded, but there it is.

No sooner than I had finished writing those closing thoughts, I tried background="" on IE. It didn't work. Changing to use backgroundColor, however, does. Which points out why the Star Trek episode was so unrealistic; none of the tribbles featured had any grey hairs (Of course, Bill Gates hadn't yet flunked out of Harvard, at that point, so maybe my antecedants were spared).

Bernard Marx

11:13 pm on Feb 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I would like to put forward a some vague hypotheses concerning the non-appearance of grey-haired tribbles:

1. Tribble fur isn't pigmented, rather the keratin analogue is naturally coloured.
- The varying colours of tribble fur do suggest pigmentation however.

2. Tribbles, much like Alphas in a certain allegorical work by Aldous Huxley, burn brightly, keeping the appearance of youth throughout, then suddenly expire.

3. Ageing tribbles, when they have lost the ability to defend themselves, are immediately set upon, and cannibalized.

4. The entire population was still quite young. Had the episode been longer, we might have indeed have seen grey-haired tribbles, and probably bald ones too. We might also have seen them experiment with various forms of social organization, and express themselves in ever more meaningless forms of popular culture. We certainly would have seen them effectively exterminate themselves by degrading their available resources beyond sustainable limits. However, shortly before this mass extinction, the green ones would have been singled out as "terror-tribbles".

Rambo Tribble

11:57 pm on Feb 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Obviously, Mr. Marx, you harbor some misconceptions as to the nature of the tribble. As was revealed on "Star Trek - Enterprise", tribbles have a long and proud history of roaming the galaxy.

Dynel hair, while extremely resilient to ageing, is no match for the machinations of one Mr. William Gates, upon whom Klingons have nothing.

Tribble longevity is, actually, quite remarkably long. My uncle (whom I'm said to favor, he was the purple one in the bridge scene with Kirk) is still quite active, though he is approaching 90.

Tribbles are predominantly vegetarians, hence their taste for quadro-triticale. I must admit to being a bit of a black sheep in this respect, early on having developed a taste for IBM salesmen.

Oh, and finally, it is we of the magenta hue that are noted for our subversive natures, though, as you might expect, we prefer the term "freedom fighters".

Rambo Tribble

3:53 am on Feb 7, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Whilst perusing some of my old files I came across a script I'd written to check a group of checkboxes and cobbled it in with the script I posted above. Here's the result:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Untitled</title>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<style type="text/css">
td{border:2px solid blue;}
tr{background:#fee;}
</style>
<script type="text/javascript">
function rowYourBoat(){
var trs=document.getElementById('tableOne').rows;
for(var i=0;i<trs.length;i++){
if(document.frmOne.elements[i].checked){
trs[i].style.backgroundColor="#eef";
}else{
trs[i].style.backgroundColor="";
}
}
}
function boxCheck(frm,stat){
var frm_el=frm.elements;
var frm_ln=frm_el.length;
for(var i=0;i<frm_ln;i++){
if(frm_el[i].type=="checkbox")frm_el[i].checked=stat;
}
}
</script>
</head>
<body>
<form action="" name="frmOne">
<table id="tableOne" onclick="rowYourBoat();">
<tr>
<td><input type="checkbox" onclick="boxCheck(this.form,this.checked);" /></td><td>data</td><td>data</td>
</tr>
<tr>
<td><input type="checkbox" /></td><td>data</td><td>data</td>
</tr>
<tr>
<td><input type="checkbox" /></td><td>data</td><td>data</td>
</tr>
<tr>
<td><input type="checkbox" /></td><td>data</td><td>data</td>
</tr>
</table>
</form>
</body>
</html>

haryanto

6:48 am on Feb 7, 2005 (gmt 0)

10+ Year Member



RAMBO,

That is exactly what I wanted.
OK, to take it a little further, is it possible to implement background color change for a row onRollover too? That will make it perfect like a Crispy Cream donut!

Rambo Tribble

2:32 pm on Feb 7, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I thought it was Krispy Kreme, but what does a tribble know about such things? Changing backgound with onmouseover and onmouseout would be easy enough, just try this:

<tr onmouseover="this.style.backgroundColor='#dbb';" onmouseout="this.style.backgroundColor='';">
<td>data</td>
</tr>

This does beg certain questions if you want to use the effect to toggle, like the checkboxes.

Bernard Marx

3:47 pm on Feb 7, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



..which is why I paid the price of entry to the ClassName Boogaloo Party in the first place. The weight behind it's (#imperfect) claims to perfection is that it can handle most situations like this without missing a beat.

I cooked up a little solution to this. It extends The Tribble Bubble, but doesn't do The Loop - since there's some querying of event objects going on anyway.

I'm sending the URL to all revellers .

Meanwhile, there are 2 solutions that are more specific to the task at hand, and so would require less code.

1. Use Rambo's approach. For the rollovers, we need to temporarily store the current directly applied styling of the element so that it can be re-applied onmouseout. To do this we can either store the initial BG color of the 'moused-over' row in a global variable, or better, for a more OOP approach, use a custom attribute or expando.

2. If all browsers were 'proper' browsers, we could forget BOTH current approaches, and simply add and remove custom attributes. The stylings could then be applied with CSS, using attribute/value selectors. No muss, no fuss.

----
# For one thing, I forgot to escape the backslashes in the RegExp constructor.

Rambo Tribble

3:50 pm on Feb 7, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Alternatively, since we toggle to a known state (or states), we can simply test if that state (or one of the target states) exists and execute accordingly.

[edited by: Rambo_Tribble at 3:55 pm (utc) on Feb. 7, 2005]

Bernard Marx

3:51 pm on Feb 7, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



mmm?

Rambo Tribble

4:01 pm on Feb 7, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



if(element.currentStyle.etc.~=="toggle_value"){
element.style.etc.~=""
}else{
element.style.etc.~="toggle_value"
}

Obviously, there would need to be some W3C nonsense, as well.

Rambo Tribble

5:05 pm on Feb 7, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The example you provided in your sticky is quite nice, Mr. Marx, but my inquiry regarding the toggle was directed at a different possibility; that haryanto wanted to replace the checkboxes with a function that changed on mouseover, then reverted on a second mouseover.

You know, like the Beatles tune,". . . mouseover once, mouseover twice! C'mon, baby, it's an I/O device . . . Traveling on the one after Red Hat 9 . . .", or something like that.