Page 1 of 2 12 LastLast
Results 1 to 10 of 20

Thread: Change TD bgColor onClick

  1. #1
    Join Date
    Aug 2005
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Change TD bgColor onClick

    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.

  2. #2
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by DanielHall
    <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 changes
    Someone else recently asked a similar question. 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.

    Code:
    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.

  3. #3
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    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:
    Code:
    <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>
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  4. #4
    Join Date
    Aug 2005
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Thank you

    Both brilliant answers. Never heard of event listeners??? I got some reading to do!!! Many many thanks!!!!!

  5. #5
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by jscheuer1
    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

  6. #6
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    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:
    Code:
    <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.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  7. #7
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by jscheuer1
    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):

    Code:
    .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

  8. #8
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    Quote Originally Posted by Mike
    As it now stands, the script cannot be used when the cells contain other elements
    Ah, so. I added this (red):
    Code:
    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:
    Code:
    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):
    HTML Code:
    <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>
    Quote Originally Posted by Mike
    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.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  9. #9
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    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?"
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  10. #10
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by jscheuer1
    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,

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

    Code:
    (('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

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •