PDA

View Full Version : Change TD bgColor onClick



DanielHall
08-17-2005, 11:55 AM
Hi ppl.

Could someone please help me with this....

I have table with several TRs. Each TR has a unique ID. Each TR contains 4 TDs. So...

<table>
<tr id="1">
<td>No.1 - Option1</td>
...
...
<td>No. 1 - Option4</td>
</tr>

<tr id="2">
and so on...

What ive tried to do, (but failed) is place onclick events in all the TDs, so when they are clicked their backgroundColor changes (by calling a js function which identifies which TR it belongs to and changes color say from white to red). BUT (and this is what i cant get to work), change any other TD's in that TR (identified by the TR's ID), that are already red, back to white. So its sort of like multiple rollover menus but onclick rather than onmouseover.

Any help whatsoever would be really appreciated.

Thank you.

Danny.

mwinter
08-17-2005, 01:57 PM
<tr id="1">The value of an id attribute cannot start with a number. It must begin with a letter.


What ive tried to do, (but failed) is place onclick events in all the TDs, so when they are clicked their backgroundColor changesSomeone else recently asked a similar question (http://www.dynamicdrive.com/forums/showthread.php?t=4341). The second solution I posted there could be used, but it would be clumsy to use as you'd have so many intrinsic events added to your markup.

Below is some code that will automatically add listeners to each row. It then uses the bubbling phase of the event model to catch click events and determine the cell from which they originated.


var global = this;

var Finaliser = (function() {
var _l = null,
_i = {
attachHandler : function(f) {
if('function' == typeof f) {_l = new Node(f, _l);}
}
};

function Node(d, n) {
this.data = d;
this.next = n;
}

_i.attachHandler(function() {_l = null;});
if(global.onunload) {_i.attachHandler(global.onunload);}

global.onunload = function() {
var n = _l;

while(n) {
n.data();
n = n.next;
}
};
return _i;
})();

function attachHighlighters(h, b) {
var i = 1,
r;

function createHighlighter() {
var a = null;

Finaliser.attachHandler(function() {a = null;});

return function(e) {
var s, t;
e = e || global.event;

if(e && (t = e.target || e.srcElement)) {
while(t && ('TD' != t.tagName) && (t != this)) {t = t.parentNode;}
if(t && (t != this) && (s = t.style)) {
if(a) {a.backgroundColor = b;}
s.backgroundColor = h;
a = s;
}
}
}
}

if(document.getElementById) {
while((r = document.getElementById('r' + i++))) {
r.onclick = createHighlighter();
}
}
r = null;
}The function, attachHighlighters, takes two arguments. The first is the highlight colour value. The second is the normal background colour, used to restore the highlight. If this value will be the same as the original colour used for each cell, then you can simply pass an empty string. You call this function when then the document has loaded to add the effect.

The code assumes that the applicable rows possess id attributes of the form, rx, where x is number greater than, or equal to, one. These numbers must be consecutive; as soon as the script fails to find an element, it will stop adding listeners.

This has been lightly tested in Firefox, but should work in others, and gracefully degrade everywhere.

Hope that helps,
Mike


Incidentally, the Finaliser object should help to prevent memory leaks in IE. It should have been included in the thread mentioned earlier (and others, no doubt), but I forgot. In all cases, the leaks shouldn't be serious though, so I won't make a big deal out of them.

jscheuer1
08-17-2005, 02:31 PM
While The above solution was being worked out, I came up with this, which works as well and seems a bit simpler. I did think about using event listeners but, it seemed more than necessary for this application:

<html>
<head>
<title>Table Clickover - Demo</title>
<script type="text/javascript">
function toggleCells(el, col1, col2){
for (i = 0; i < el.parentNode.childNodes.length; i++)
if (el.parentNode.childNodes[i].tagName)
el.parentNode.childNodes[i].style.backgroundColor=col2
el.style.backgroundColor=col1
}
</script>
</head>
<body>
<table>
<tr>
<td style="background-color:white;" onclick="toggleCells(this, 'red', 'white')">&nbsp</td><td style="background-color:white;" onclick="toggleCells(this, 'red', 'white')">&nbsp</td><td style="background-color:white;" onclick="toggleCells(this, 'red', 'white')">&nbsp</td>
</tr>
<tr>
<td style="background-color:blue;" onclick="toggleCells(this, 'orange', 'blue')">&nbsp</td><td style="background-color:blue;" onclick="toggleCells(this, 'orange', 'blue')">&nbsp</td><td style="background-color:blue;" onclick="toggleCells(this, 'orange', 'blue')">&nbsp</td>
</tr>
<tr>
<td style="background-color:pink;" onclick="toggleCells(this, 'green', 'pink')">&nbsp</td><td style="background-color:pink;" onclick="toggleCells(this, 'green', 'pink')">&nbsp</td><td style="background-color:pink;" onclick="toggleCells(this, 'green', 'pink')">&nbsp</td>
</tr>
</table>

</body>
</html>

DanielHall
08-17-2005, 02:54 PM
Both brilliant answers. Never heard of event listeners??? I got some reading to do!!! Many many thanks!!!!!

mwinter
08-17-2005, 04:56 PM
While The above solution was being worked out, I came up with this, which works as well and seems a bit simpler.Indeed the code is simpler, and its usage is similar to the solutions I proposed in the other thread. However, I think this usage - adding intrinsic events to every cell - is unworkable. At least in the long term.

I'm not saying my solution is superior - it has its own weaknesses - but it's definitely easier to use.


function toggleCells(el, col1, col2){
for (i = 0; i < el.parentNode.childNodes.length; i++)The variable, i, will leak into the global namespace. Use the var keyword. It's not damaging, I know, but it's good practice.


if (el.parentNode.childNodes[i&#93;.tagName)Checking for a tagName property would seem like a good idea at first, except for the fact that SGML comments can be accessed from the DOM using the childNodes collection, and they have tagName properties. Add to that the fact that some WYSIWYG software injects comments into markup, and some might use it legitimately for documentation purposes, and this approach becomes dubious.

The simple fix is to substitute the childNodes collection for the cells collection.

Mike

jscheuer1
08-18-2005, 04:10 PM
Mike, I rewrote my script and markup, taking advantage of your suggestions and adding in an event listener so as to simplify things considerably for the end user while retaining the advantage of being able to use different 'color sets' for each row:

<html>
<head>
<style type="text/css">
table {
cursor:text;
}
td {
font-size:.5ex;
cursor:default;
}
</style>
<title>Table Clickover - Demo</title>
<script type="text/javascript">
var el
function togCell(col){
if (typeof event!=='undefined')
el=event.srcElement
for (var i = 0; i < el.parentNode.cells.length; i++)
el.parentNode.cells[i].style.backgroundColor=''
el.style.backgroundColor=col
}
if (window.addEventListener)
window.addEventListener('click', function(e){el=e.target}, true)
</script>
</head>
<body>
<table border="1" cellpadding="8" cellspacing="9">
<tr style="background-color:white;">
<td onclick="togCell('red')">&nbsp</td><td onclick="togCell('red')">&nbsp</td><td onclick="togCell('red')">&nbsp</td>
</tr>
<tr style="background-color:blue;">
<td onclick="togCell('orange')">&nbsp</td><td onclick="togCell('orange')">&nbsp</td><td onclick="togCell('orange')">&nbsp</td>
</tr>
<tr style="background-color:pink;">
<td onclick="togCell('green')">&nbsp</td><td onclick="togCell('green')">&nbsp</td><td onclick="togCell('green')">&nbsp</td>
</tr>
</table>
</body>
</html>I also tested out your version in IE6, worked like a charm. I am intrigued with the fact that you mention and used additional code to work around IE's known memory leak bug. I've been working on doing the same thing for a DOM gallery I've written. In my experience with that so far, it would be impossible to be certain if your code avoids the bug without reloading the page virtually countless times or, alternatively, using it with an extremely huge table. The leak, as I've encountered it, is imperceptible on small markups rendered (loaded) only a few times.

mwinter
08-19-2005, 11:18 AM
Mike, I rewrote my script and markup, taking advantage of your suggestions and adding in an event listener so as to simplify things considerably for the end user [...]Unfortunately in doing so, you introduced a problem that you avoided in your first version. As it now stands, the script cannot be used when the cells contain other elements. If one of these descendents is clicked, el will not reference the cell and the parentNode property will not reference the row. The script will error out upon resolving a property of the cells collection as it doesn't exist.

You'll need to do what I do: walk up the DOM tree looking for a cell. That will be your el value.


while retaining the advantage of being able to use different 'color sets' for each row:Were I to add that (and I chose not to, unless someone asks for it), I'd likely use CSS. A class, highlighted, could be added to the active cell. The class could have a default colour scheme, which could be overridden in both specific (by adding an id attribute to a row) and multiple cases (by adding a class attribute):


.highlighted {
background-color: red;
color: black;
}

#myRow .highlighted {
background-color: black;
color: white;
}


I am intrigued with the fact that you mention and used additional code to work around IE's known memory leak bug.I should have used it anywhere a leak may occur in previous code, but it's not an issue I often think about.


The leak, as I've encountered it, is imperceptible on small markups rendered (loaded) only a few times.Yes, usually. However, the issue isn't really with one single document or even one site, but rather the cumulative effect across many.

Consider a script such as HV Menu. If it caused a memory leak (it might, I haven't looked closely at the code), then there are many sites that will contribute to an ever-growing leak.

I see it as a matter of not playing a part in this problem, rather than thinking that I alone might bring down a system (because that's extremely unlikely).

You'd have thought that Microsoft would have released a patch by now, wouldn't you?

Mike

jscheuer1
08-19-2005, 06:09 PM
As it now stands, the script cannot be used when the cells contain other elementsAh, so. I added this (red):

var el
function togCell(col){
if (typeof event!=='undefined')
el=event.srcElement
while(el.tagName!=='TD')
el=el.parentNode
. . .But, that will not help if there is a nested table. Your version also seems to fail on a nested table. So, I've opted for a class name test, requiring the markup to include a class name on the td that has the onclick event:

var el
function togCell(col){
if (typeof event!=='undefined')
el=event.srcElement
while(el.className!=='togC')
el=el.parentNode
. . .and for the markup (nested table included as an example):

<td class="togC" onclick="togCell('red')"><table><tr><td><img src="spacer.gif" style="width:10px;height:10px;background-color:black;">&nbsp</td></tr></table></td>

You'd have thought that Microsoft would have released a patch by now, wouldn't you?Yah, except for the fact that, at least as I understand it, Bill has never thought memory to be a very big issue, that is why the original DOS had so little. Besides, they have their hands full over there in Redmond just trying to keep ahead of the latest worm. It's hard being number one.

jscheuer1
08-19-2005, 06:19 PM
Oh, and I almost forgot. The reason I mentioned the memory leak being so difficult to detect on a small markup loaded only a few times was not to say, in essence, "why bother?" Rather to say, "How would you know if the measures you are taking to prevent the leak are effective?"

mwinter
08-19-2005, 10:34 PM
Your version also seems to fail on a nested table.Yes, but in a well-written document, nested tables will either be extremely rare, or non-existent. However, adapting mine should be trivial. Change the expression,


('TD' != t.tagName)in the while condition to:


(('TD' != t.tagName) || (this != t.parentNode))In fact, assuming valid markup, you could omit the tagName check as only table cells should appear as children of table rows (yes, comments can, but they will never be event targets).


[...] at least as I understand it, Bill has never thought memory to be a very big issue, that is why the original DOS had so little.As I recall, DOS had so little for two reasons. The first was that early processors could access large amounts of memory as they weren't capable of addressing that far. The second was that to address larger regions, the processor needed to be switched into protected mode, which is a rather involved process (and what device drivers like EMM386 did).


The reason I mentioned the memory leak being so difficult to detect on a small markup loaded only a few times was not to say, in essence, "why bother?" Rather to say, "How would you know if the measures you are taking to prevent the leak are effective?"The memory leak is caused by a reference loop that involves a host object, such as an ActiveX object or a DOM object. As host objects aren't controlled by JScript, it cannot see the insignificance of the loop, so it keeps all of the objects involved in memory. If you break the loop, there's nothing to stop the interpreter from clearing up properly.

Thinking about it, I'm not sure if my code would actually cause a leak as a is the style object of an element, not the object itself. If I made the alterations previously discussed, the Finaliser mechanism certainly would be necessary. Still, it demonstrates a point.

Mike

sleipner
11-10-2005, 05:06 PM
nvm that post I made about 30 minutes ago, I don't know much of anything about javascript, but I copied the function and changed the name (so that I have 2 of them, just with different names and the colors reversed) and called on the 2nd one with the different name onmouseout and it changes color back

clueo8
07-25-2006, 03:51 PM
Almost a year later, I come across this posting...

I'm looking to do this similar td background change... but in a vertical table which contains only 1 column(td) per row(tr). For example:

My table is like this:


<table>
<tr>
<td onclick="toggleCells(this, '#FFFFFF', '#E7EFFF')">#</td>
</tr>
<tr>
<td onclick="toggleCells(this, '#FFFFFF', '#E7EFFF')">#</td>
</tr>
<tr>
<td onclick="toggleCells(this, '#FFFFFF', '#E7EFFF')">#</td>
</tr>
</table>


In this example code given in this forum, it only toggles the colors between elements in the same row(tr)... I'd like to do it between all the elements(td's) in all of the rows(tr's).

Thanks in Advance... I hope someone is still out there on this one...

jscheuer1
07-25-2006, 03:57 PM
You could probably adapt the functions in this thread:

http://www.dynamicdrive.com/forums/showthread.php?t=11390

to your purposes.

clueo8
07-25-2006, 04:46 PM
Thanks for the post!

Although, It seems like this example also only changes the bgcolor based upon the columns(td's) rather then on the rows(tr's)

jscheuer1
07-25-2006, 04:55 PM
With only one td per row, what's the difference? In any case, it has been my experience that the styling of rows in a table cannot be relied upon across browsers whereas, td styles appear to be consistently supported.

clueo8
07-25-2006, 06:44 PM
Are you saying that what I need can't be done?

jscheuer1
07-25-2006, 06:56 PM
No, just that it may be better to approach it from the point of view of the table cells. If you can get enough of the right table cells to do the same thing, it is just like getting a row or a column to do it, provided that your table is styled appropriately.

Did you try out my demo from:

http://www.dynamicdrive.com/forums/showthread.php?t=11390

If not, try it out. If you have actually loaded it in your browser, what exactly would it need to do or look like that it doesn't already do or look like? If you want different event triggers and/or want to limit the trigger spots to a particular portion of the table, how exactly do you want it to work? If it would need to look differently (the number of rows and/or columns) how many of each should it have?

clueo8
07-26-2006, 12:45 PM
It turns out that for the project I'm working on... the navigation I'm making within my table is going to be static on each page... So the thing I wanted is not needed no longer... Thanks for the help!

shyne
03-17-2007, 08:15 AM
Hi

I wanted to know if someone couldplease help me.
I need to know how can I use one of the code examples provided in this topic to mke it show a color also on mouseover? Rightnow the color change for each TD works when you click on a cell but I want a color change when you move your mouse over too.

Thanksin advance

jscheuer1
03-17-2007, 03:52 PM
Hi

I wanted to know if someone couldplease help me.
I need to know how can I use one of the code examples provided in this topic to mke it show a color also on mouseover? Rightnow the color change for each TD works when you click on a cell but I want a color change when you move your mouse over too.

Thanksin advance

This is a long thread and at least two code approaches to the effect in question have been mentioned in it.

Generally, just changing onclick to onmouseover will do the trick but, in specific cases other common sense things need to be done as well. Like, onclick is often a toggle while with onmouseover you generally want the toggle spread between onmouseover and onmouseout though this isn't always the case.

Set up a demo of what you are trying to do. If you have problems, start a new thread and ask for help with it. It always helps us help you if you can provide a link to your demo. A demo helps us help you even if it doesn't work.