Set colspan dynamically with jQuery

JqueryHtml Table

Jquery Problem Overview


I have a simple table structure like this. What I would like to do is to dynamically merge some columns based on some condition within the <td> for example, if td1 and td3 are empty then merge the cells and do <td class="col1" colspan="3">1Meeting</td> I tried playing around with jQuery using:

 $(".tblSimpleAgenda  td:contains('')").hide();

but it had no effect.

What would be the the best way using jQuery to achieve this.

<table  class="tblSimpleAgenda" cellpadding="5" cellspacing="0">
 <tbody>
 <th align="left">Time</th>
 <th align="left">Room 1</th>
 <th align="left">Room 2</th>
 <th align="left">Room 3</th> 
    
        <tr valign="top">
            <td class="colTime">09:00 – 10:00</td>
            <td class="col1"></td>
            <td class="col2">Meeting 2</td>
		    <td class="col3"></td>
        </tr>
        
        <tr valign="top">
            <td class="colTime">10:00 – 10:45</td>
            <td class="col1">Meeting 1</td>
            <td class="col2">Meeting 2</td>
		    <td class="col3">Meeting 3</td>	
        </tr>
        
        <tr valign="top">
            <td class="colTime">11:00 – 11:45</td>
            <td class="col1">Meeting 1</td>
            <td class="col2">Meeting 2</td>
		    <td class="col3">Meeting 3</td>	
        </tr>
</tbody>
</table> 

Jquery Solutions


Solution 1 - Jquery

How about

$([your selector]).attr('colspan',3);

I would imagine that to work but have no way to test at the moment. Using .attr() would be the usual jQuery way of setting attributes of elements in the wrapped set.

As has been mentioned in another answer, in order to get this to work would require removing the td elements that have no text in them from the DOM. It may be easier to do this all server side

EDIT:

As was mentioned in the comments, there is a bug in attempting to set colspan using attr() in IE, but the following works in IE6 and FireFox 3.0.13.

Working Demo

notice the use of the attribute colSpan and not colspan - the former works in both IE and Firefox, but the latter does not work in IE. Looking at jQuery 1.3.2 source, it would appear that attr() attempts to set the attribute as a property of the element if

  1. it exists as a property on the element (colSpan exists as a property and defaults to 1 on <td> HTMLElements in IE and FireFox)
  2. the document is not xml and
  3. the attribute is none of href, src or style

using colSpan as opposed to colspan works with attr() because the former is a property defined on the element whereas the latter is not.

the fall-through for attr() is to attempt to use setAttribute() on the element in question, setting the value to a string, but this causes problems in IE (bug #1070 in jQuery)

// convert the value to a string (all browsers do this but IE) see #1070
elem.setAttribute( name, "" + value ); 

In the demo, for each row, the text in each cell is evaluated. If the text is a blank string, then the cell is removed and a counter incremented. The first cell in the row that does not have class="colTime" has a colspan attribute set to the value of the counter + 1 (for the span it occupies itself).

After this, for each row, the text in the cell with class="colspans" is set to the colspan attribute values of each cell in the row from left to right.

HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<title>Sandbox</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { background-color: #000; font: 16px Helvetica, Arial; color: #fff; }
td { text-align: center; }
</style>
</head>
<body>
<table  class="tblSimpleAgenda" cellpadding="5" cellspacing="0">
 <tbody>
        <tr>
            <th align="left">Time</th>
            <th align="left">Room 1</th>
            <th align="left">Room 2</th>
            <th align="left">Room 3</th> 
            <th align="left">Colspans (L -> R)</th>
        </tr>
        <tr valign="top">
            <td class="colTime">09:00 – 10:00</td>
            <td class="col1"></td>
            <td class="col2">Meeting 2</td>
            <td class="col3"></td>
            <td class="colspans">holder</td>
        </tr>

        <tr valign="top">
            <td class="colTime">10:00 – 10:45</td>
            <td class="col1">Meeting 1</td>
            <td class="col2">Meeting 2</td>
            <td class="col3">Meeting 3</td>    
             <td class="colspans">holder</td> 
        </tr>

        <tr valign="top">
            <td class="colTime">11:00 – 11:45</td>
            <td class="col1">Meeting 1</td>
            <td class="col2">Meeting 2</td>
            <td class="col3">Meeting 3</td>
            <td class="colspans">holder</td>     
        </tr>
        
        <tr valign="top">
            <td class="colTime">11:00 – 11:45</td>
            <td class="col1">Meeting 1</td>
            <td class="col2">Meeting 2</td>
            <td class="col3"></td>
            <td class="colspans">holder</td>     
        </tr>
</tbody>
</table>

</body>
</html>

jQuery code

$(function() {

  $('table.tblSimpleAgenda tr').each(function() {
    var tr = this;
    var counter = 0;
        
    $('td', tr).each(function(index, value) {
      var td = $(this);
      
      if (td.text() == "") {
        counter++;
        td.remove();
      }
    });
    
    if (counter !== 0) {
      $('td:not(.colTime):first', tr)
        .attr('colSpan', '' + parseInt(counter + 1,10) + '');
    }
  });

  $('td.colspans').each(function(){
    var td = $(this);
    var colspans = [];
    
    td.siblings().each(function() {
      colspans.push(($(this).attr('colSpan')) == null ? 1 : $(this).attr('colSpan'));
    });
    
    td.text(colspans.join(','));
  });

});

This is just a demonstration to show that attr() can be used, but to be aware of it's implementation and the cross-browser quirks that come with it. I've also made some assumptions about your table layout in the demo (i.e. apply the colspan to the first "non-Time" cell in each row), but hopefully you get the idea.

Solution 2 - Jquery

I have adapted the script from Russ Cam (thank you, Russ Cam!) to my own needs: I needed to merge any columns that had the same value, not just empty cells.

This could be useful to someone else... Here is what I have come up with:

jQuery(document).ready(function() {

   jQuery('table.tblSimpleAgenda tr').each(function() {
    var tr = this;
    var counter = 0;
	var strLookupText = '';

    jQuery('td', tr).each(function(index, value) {
      var td = jQuery(this);

      if ((td.text() == strLookupText) || (td.text() == "")) {
        counter++;
		td.prev().attr('colSpan', '' + parseInt(counter + 1,10) + '').css({textAlign : 'center'});
        td.remove();
      }
	  else {
	    counter = 0;
	  }
	  
	  // Sets the strLookupText variable to hold the current value. The next time in the loop the system will check the current value against the previous value.
	  strLookupText = td.text();
	  
    });

  });
  
});

Solution 3 - Jquery

You'd need to remove the blank table cell element entirely, and change the colspan attribute on another cell in the row to encompass the released space, e.g.:

refToCellToRemove.remove();
refTocellToExpand.colspan = 4;

Note that setting it via setAttribute (which would otherwise be correct) will not work properly on IE.

Beware: IE does some very strange table layout things when you muck about with colspans dynamically. If you can avoid it, I would.

Solution 4 - Jquery

I've also found that if you had display:none, then programmatically changed it to be visible, you might also have to set

$tr.css({display:'table-row'});

rather than display:inline or display:block otherwise the cell might only show as taking up 1 cell, no matter how large you have the colspan set to.

Solution 5 - Jquery

td.setAttribute('rowspan',x);

Solution 6 - Jquery

Setting colspan="0" is support only in firefox.

In other browsers we can get around it with:

// Auto calculate table colspan if set to 0
var colCount = 0;
$("td[colspan='0']").each(function(){
	colCount = 0;
	$(this).parents("table").find('tr').eq(0).children().each(function(){
        if ($(this).attr('colspan')){
            colCount += +$(this).attr('colspan');
        } else {
            colCount++;
        }
    });
$(this).attr("colspan", colCount);
});

http://tinker.io/3d642/4

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTerry MarderView Question on Stackoverflow
Solution 1 - JqueryRuss CamView Answer on Stackoverflow
Solution 2 - JqueryMarcos BuarqueView Answer on Stackoverflow
Solution 3 - JqueryT.J. CrowderView Answer on Stackoverflow
Solution 4 - JqueryJayCrosslerView Answer on Stackoverflow
Solution 5 - JqueryJoshuaView Answer on Stackoverflow
Solution 6 - JqueryJohn MagnoliaView Answer on Stackoverflow