Question

I have a table that kind of expands and collapses, but it's getting too messy to use it and IE and Firefox are not working properly with it.

So, here's the JavaScript code:

  function toggle_it(itemID){ 
      // Toggle visibility between none and '' 
      if ((document.getElementById(itemID).style.display == 'none')) { 
            document.getElementById(itemID).style.display = '' 
            event.preventDefault()
      } else { 
            document.getElementById(itemID).style.display = 'none'; 
            event.preventDefault()
      }    
  } 

And a Sample HTML:

<table>
    <tr>
        <td>Product</td>
        <td>Price</td>
        <td>Destination</td>
        <td>Updated on</td>
    </tr>
    <tr>
        <td>Oranges</td>
        <td>100</td>
        <td><a href="#" id="toggle" onClick="toggle_it('tr1');toggle_it('tr2')">+ On Store</a></td>
        <td>22/10</td>
    </tr>
    <tr id="tr1" style="display:none">
        <td></td>
        <td>120</td>
        <td>City 1</td>
        <td>22/10</td>
    </tr>
    <tr id="tr2" style="display:none">
        <td></td>
        <td>140</td>
        <td>City 2</td>
        <td>22/10</td>
    </tr>
    <tr>
        <td>Apples</td>
        <td>100</td>
        <td><a href="#" id="toggle" onClick="toggle_it('tr3');toggle_it('tr4')">+ On Store</a></td>
        <td>22/10</td>
    </tr>
    <tr id="tr3" style="display:none">
        <td></td>
        <td>120</td>
        <td>City 1</td>
        <td>22/10</td>
    </tr>
    <tr id="tr4" style="display:none">
        <td></td>
        <td>140</td>
        <td>City 2</td>
        <td>22/10</td>
    </tr>
</table>

The problem is that I use one ID for each and every and that's very annoying because I want to have a lot of hidden rows for each parent and a lot of parents, so it would be too many IDs to handle. And IE and FireFox are only showing the first Hidden Row and not the others. I suspect this happens because I've made it work by triggering all IDs together. I think it would be better if I use Classes instead of IDs to indetify the hidden rows.

I'm really new to all of this so please try and explaining it in any kind of simply way. Also I've tried jQuery but wasn't able to get it.

Was it helpful?

Solution

It's difficult to figure out what you're trying to do with this sample but you're actually on the right track thinking about using classes. I've created a JSFiddle to help demonstrate a slightly better way (I hope) of doing this.

Here's the fiddle: link.

What you do is, instead of working with IDs, you work with classes. In your code sample, there are Oranges and Apples. I treat them as product categories (as I don't really know what your purpose is), with their own ids. So, I mark the product <tr>s with class="cat1" or class="cat2".

I also mark the links with a simple .toggler class. It's not good practice to have onclick attributes on elements themselves. You should 'bind' the events on page load using JavaScript. I do this using jQuery.

$(".toggler").click(function(e){
    // you handle the event here
});

With this format, you are binding an event handler to the click event of links with class toggler. In my code, I add a data-prod-cat attribute to the toggler links to specify which product rows they should control. (The reason for my using a data-* attribute is explained here. You can Google 'html5 data attributes' for more information.)

In the event handler, I do this:

$('.cat'+$(this).attr('data-prod-cat')).toggle();

With this code, I'm actually trying to create a selector like $('.cat1') so I can select rows for a specific product category, and change their visibility. I use $(this).attr('data-prod-cat') this to access the data-prod-cat attribute of the link the user clicks. I use the jQuery toggle function, so that I don't have to write logic like if visible, then hide element, else make it visible like you do in your JS code. jQuery deals with that. The toggle function does what it says and toggles the visibility of the specified element(s).

I hope this was explanatory enough.

OTHER TIPS

Well one way to do it would be to just put a class on the "parent" rows and remove all the ids and inline onclick attributes:

<table id="products">
    <thead>
    <tr>
        <th>Product</th>
        <th>Price</th>
        <th>Destination</th>
        <th>Updated on</th>
    </tr>
    </thead>
    <tbody>
    <tr class="parent">
        <td>Oranges</td>
        <td>100</td>
        <td><a href="#">+ On Store</a></td>
        <td>22/10</td>
    </tr>
    <tr>
        <td></td>
        <td>120</td>
        <td>City 1</td>
        <td>22/10</td>
    </tr>
    <tr>
        <td></td>
        <td>140</td>
        <td>City 2</td>
        <td>22/10</td>
    </tr>
    ...etc.
    </tbody>
</table>

And then have some CSS that hides all non-parents:

tbody tr {
    display : none;          // default is hidden
}
tr.parent {
    display : table-row;     // parents are shown
}
tr.open {
    display : table-row;     // class to be given to "open" child rows
}

That greatly simplifies your html. Note that I've added <thead> and <tbody> to your markup to make it easy to hide data rows and ignore heading rows.

With jQuery you can then simply do this:

// when an anchor in the table is clicked
$("#products").on("click","a",function(e) {
    // prevent default behaviour
    e.preventDefault();
    // find all the following TR elements up to the next "parent"
    // and toggle their "open" class
    $(this).closest("tr").nextUntil(".parent").toggleClass("open");
});

Demo: http://jsfiddle.net/CBLWS/1/

Or, to implement something like that in plain JavaScript, perhaps something like the following:

document.getElementById("products").addEventListener("click", function(e) {
    // if clicked item is an anchor
    if (e.target.tagName === "A") {
        e.preventDefault();
        // get reference to anchor's parent TR
        var row = e.target.parentNode.parentNode;
        // loop through all of the following TRs until the next parent is found
        while ((row = nextTr(row)) && !/\bparent\b/.test(row.className))
            toggle_it(row);
    }
});

function nextTr(row) {
    // find next sibling that is an element (skip text nodes, etc.)
    while ((row = row.nextSibling) && row.nodeType != 1);
    return row;
}

function toggle_it(item){ 
     if (/\bopen\b/.test(item.className))       // if item already has the class
         item.className = item.className.replace(/\bopen\b/," "); // remove it
     else                                       // otherwise
         item.className += " open";             // add it
}

Demo: http://jsfiddle.net/CBLWS/

Either way, put the JavaScript in a <script> element that is at the end of the body, so that it runs after the table has been parsed.

JQuery 10.1.2 has a nice show and hide functions that encapsulate the behavior you are talking about. This would save you having to write a new function or keep track of css classes.

$("tr1").show();

$("tr1").hide();

w3cSchool link to JQuery show and hide

event.preventDefault()

Doesn't work in all browsers. Instead you could return false in OnClick event.

onClick="toggle_it('tr1');toggle_it('tr2'); return false;">

Not sure if this is the best way, but I tested in IE, FF and Chrome and its working fine.

Below is my Script which show/hide table row with id "agencyrow".

<script type="text/javascript">

                        function showhiderow() {
                            if (document.getElementById("<%=RadioButton1.ClientID %>").checked == true) {

                                document.getElementById("agencyrow").style.display = '';
                            } else {

                                document.getElementById("agencyrow").style.display = 'none';
                            }


                        }
    </script> 

Just call function showhiderow()upon radiobutton onClick event

AngularJS directives ng-show, ng-hide allows to display and hide a row:

   <tr ng-show="rw.isExpanded">
   </tr>

A row will be visible when rw.isExpanded == true and hidden when rw.isExpanded == false. ng-hide performs the same task but requires inverse condition.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top