jQuery merge table rows, but take previous columns into account

12,040

If only the first column is supposed to be a "divider" for the rest of the columns, then you could use an array to store first column rows "breaks".

Also, your function doesn't have the right to work. When element is removed inside loop, The index of each element above the removed one is shifted down immediately to fill the DOM index gap (so the element right after the removed one is skipped in next iteration). You could use "decremental" loop or simply hide td's.

function MergeCommonRows(table) {
    var firstColumnBrakes = [];
    // iterate through the columns instead of passing each column as function parameter:
    for(var i=1; i<=table.find('th').length; i++){
        var previous = null, cellToExtend = null, rowspan = 1;
        table.find("td:nth-child(" + i + ")").each(function(index, e){
            var jthis = $(this), content = jthis.text();
            // check if current row "break" exist in the array. If not, then extend rowspan:
            if (previous == content && content !== "" && $.inArray(index, firstColumnBrakes) === -1) {
                // hide the row instead of remove(), so the DOM index won't "move" inside loop.
                jthis.addClass('hidden');
                cellToExtend.attr("rowspan", (rowspan = rowspan+1));
            }else{
                // store row breaks only for the first column:
                if(i === 1) firstColumnBrakes.push(index);
                rowspan = 1;
                previous = content;
                cellToExtend = jthis;
            }
        });
    }
    // now remove hidden td's (or leave them hidden if you wish):
    $('td.hidden').remove();
}

$('.button').click(function(){
    MergeCommonRows($('#tbl'));
});
table {
    border-collapse: collapse;
}

th, td {
    border: 1px solid black;
    padding:5px;
    text-align: center;
}

.hidden{
    display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<table id=tbl>
    <thead>
        <tr>
            <th>column 1</th>
            <th>column 2</th>
            <th>column 3</th>
            <th>column 4</th>
            <th>column 5</th>
            <th>column 6</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>John</td>
            <td>Green</td>
            <td>apples</td>
            <td>February</td>
            <td>cow</td>
            <td>23</td>
        </tr>
        <tr>
            <td>John</td>
            <td>Red</td>
            <td>Oranges</td>
            <td>February</td>
            <td>lion</td>
            <td>18</td>
        </tr>
        <tr>
            <td>John</td>
            <td>Blue</td>
            <td>apples</td>
            <td>February</td>
            <td>cow</td>
            <td>45</td>
        </tr>
        <tr>
            <td>Mary</td>
            <td>Blue</td>
            <td>Oranges</td>
            <td>April</td>
            <td>cow</td>
            <td>23</td>
        </tr>
        <tr>
            <td>Mary</td>
            <td>Blue</td>
            <td>apples</td>
            <td>May</td>
            <td>cow</td>
            <td>49</td>
        </tr>
        <tr>
            <td>Mary</td>
            <td>green</td>
            <td>apples</td>
            <td>June</td>
            <td>cat</td>
            <td>67</td>
        </tr>
        <tr>
            <td>Mary</td>
            <td>red</td>
            <td>apples</td>
            <td>June</td>
            <td>mouse</td>
            <td>32</td>
        </tr>
    </tbody>
</table>

<p><button class=button>Merge Rows</button></p>

Share:
12,040
newuser
Author by

newuser

Updated on June 13, 2022

Comments

  • newuser
    newuser almost 2 years

    I have a table in html. The table utilizes generic tr's and td's... and makes a dynamic table with six columns and a variable number of rows.

    If a given table looks something like this:

    |column 1|column 2|column 3|column 4|column 5|column 6|
    -------------------------------------------------------
    |  John  |  Green |apples  |February|  cow   |   23   |
    -------------------------------------------------------
    |  John  |  Red   |Oranges |February|  lion  |   18   |
    -------------------------------------------------------
    |  John  |  Blue  |apples  |February|  cow   |   45   |
    -------------------------------------------------------
    |  Mary  |  Blue  |oranges |  April |  cow   |   23   |
    -------------------------------------------------------
    |  Mary  |  Blue  |apples  |   May  |  dog   |   49   |
    -------------------------------------------------------
    |  Mary  |  green |apples  |  June  |  cat   |   67   |
    -------------------------------------------------------
    |  Mary  |  red   |apples  |  June  |  mouse |   32   |
    -------------------------------------------------------
    

    When I run the following javascript:

    function MergeCommonRows(table, columnIndexToMerge) {
    previous = null;
    cellToExtend = null;
    table.find("td:nth-child(" + columnIndexToMerge + ")").each(function() {
        jthis = $(this);
        content = jthis.text()
        if (previous == content && content !== "") {
            jthis.remove();
            if (cellToExtend.attr("rowspan") == undefined) {
                cellToExtend.attr("rowspan", 2);
            }
            else {
                currentrowspan = parseInt(cellToExtend.attr("rowspan"));
                cellToExtend.attr("rowspan", currentrowspan + 1);
            }
        }
        else {
            previous = content;
            cellToExtend = jthis;
        }
    });
    }
    

    The following table is made:

    |column 1|column 2|column 3|column 4|column 5|column 6|
    -------------------------------------------------------
    |        |  Green |apples  |        |  cow   |   23   |
             ------------------         -------------------
    |  John  |  Red   |Oranges |February|  lion  |   18   |
             ------------------         -------------------
    |        |        |apples  |        |        |   45   |
    ---------         ------------------         ----------
    |        |  Blue  |oranges | April  |  cow   |   23   |
                      ------------------         ----------
    |  Mary  |        |        |  May   |        |   49   |
              --------         ----------------------------
    |        |  green | apples |  June  |  cat   |   67   |
              --------         ----------------------------
    |        |  red   |        |  July  |  mouse |   32   |
    -------------------------------------------------------
    

    Now, the javascript works in the sense that I do need the rows to merge as seen in the above table. The first column merges nicely. And other areas in the columns do so as well. My only issues arises in areas like columns 2 and five. Now to reiterate, these tables will always be dynamically generated so I can't approach this in a static fashion. But... the merging for "blue" in column 2 and "cow" in column 5 goes past the associated values in column 1. Instead, I would want a table like this:

    |column 1|column 2|column 3|column 4|column 5|column 6|
    -------------------------------------------------------
    |        |  Green |apples  |        |  cow   |   23   |
             ------------------         -------------------
    |  John  |  Red   |Oranges |February|  lion  |   18   |
             ------------------         -------------------
    |        |  Blue  |apples  |        |  cow   |   45   |
    -------------------------------------------------------
    |        |  Blue  |oranges | April  |  cow   |   23   |
                      ------------------         ----------
    |  Mary  |        |        |  May   |        |   49   |
              --------         ----------------------------
    |        |  green | apples |  June  |  cat   |   67   |
              --------         ----------------------------
    |        |  red   |        |  July  |  mouse |   32   |
    -------------------------------------------------------
    

    In the above table, the merged cells for "blue" and "cow" separate because the cells preceding it end their rowspan there. This would occur in any case. If a cell in the second column happened to span multiple rows, then any subsequent columns could not have rowspans extending past it. Hopefully what I have described is clear enough. I am asking... how do I revise my javascript to achieve this effect?