Merge and split table cells with JavaScript

REDIPS.table is small JavaScript library which enables interactive or through script merging and splitting table cells. REDIPS.table.onMouseDown() public method will activate onMouseDown event listeners on TD elements to enable mark cells with mouse button. Additional feature is appending / deleting table rows / cells. Click on image below to see live demo and try to mark cells with button click and then click on Merge or Split in toolbox.

REDIPS.table should be initialized. In demo mode, lib will show cell index in every table cell so it’s easier to see index changes after cell is merged or splitted.

// REDIPS.table initialization
redips.init = function () {
    // define reference to the REDIPS.table object
    var rt = REDIPS.table;
    // activate onMouseDown event listener on cells within table with id="mainTable"
    rt.onMouseDown('mainTable', true);
    // show cellIndex (it is nice for debugging)
    rt.cellIndex(true);
    // define background color for marked cell
    rt.color.cell = '#9BB3DA';
};

Here is JS code executed on button click in toolbox above main table. To merge table cells, cells should be marked in a sequence (horizontally or vertically). On the other hand, cell can be split if colspan or rowspan value is greater then 1.

// function merges table cells
redips.merge = function () {
    // first merge cells horizontally and leave cells marked
    REDIPS.table.merge('h', false);
    // then merge cells vertically and clear cells (second param is true by default)
    REDIPS.table.merge('v');
};

// function splits table cells if colspan/rowspan is greater then 1
// mode is 'h' or 'v' (cells should be marked before)
redips.split = function (mode) {
    REDIPS.table.split(mode);
};

// insert/delete table row
redips.row = function (type) {
    REDIPS.table.row('mainTable', type);
};

// insert/delete table column
redips.column = function (type) {
    REDIPS.table.column('mainTable', type);
};

Features like adding / deleting table rows and columns in REDIPS.table library are developed from JavaScript functions published in my previous post Adding table rows and columns in JavaScript. There you can see simple functions for adding and deleting table rows / columns but without colspan / rowspan functionality.

redips12.tar.gz package contains source code, minimized library version redips-table-min.js and several examples including this already shown on page. Further, you can see REDIPS.table documentation where are listed all methods with input parameters.

43 thoughts on “Merge and split table cells with JavaScript”

  1. The REDIPS.drag.save_content(‘table2’) gives you the row and cell index. Is there a way to get the innerHTML of the TR and TD that the row, cell index refer to by only using the row, cell index? I am having different images being placed in the TD and I would like to be able to save what the user is placing in that element.

  2. Of course, after I ask the question, I find the answer.

    var table = document.getElementById("table");
    var x = table.rows[0].cells[1];
    $('#messagearea').html(x);
    
  3. I’m glad you have found the answer and post a comment to be useful for others.
    Cheers!

  4. Hi Dbunic,
    your all codes are very helpful, but I am developing a project dashboard (it’s like excel table grid).

    Requirements are:
    1) adding columns deleting columns, adding rows deleting rows dynamically
    2) merge columns dynamically
    3) columns should be editable (if user is editing column then it stored in databases)
    4) there should be color scheme for columns so that user can specify the color of the each column dynamically. (ex: if user wants to look column in blue color it can do that dynamically any time)

    Can all these requirements handle at the same time, if possible please guide me, how to do this.

  5. @Manu – I’m glad you like my work. REDIPS.table should give you basic functionality for dynamic table management like adding / deleting table rows / columns and merging / splitting table cells.

    Editing table cells and changing background color should be possible by attaching onclick event handler. Instead of single click, editing TD content can be started with double click – ondblclick. So, when user makes double click on table cell you can show up popup to enable changing TD content. Popup will need only reference of table cell where to write input text.

    Well, this is just a hint how to start your project and I hope this lines will be helpful for you …

  6. I am developing a google like spreadsheet. I wish this will be the answer for me on merging celss. . Thanks!! Salute!

  7. Only issue i see is that when you merge say 2 cols x 5 rows the whole table resizes to the width of one column which is incorrect. An idea would be to set the height or width of the cells and multiply by the rowspan or colspan values accordingly upon merging – but i cant see where to do this!!! :) this is the only thing stopping me from implementing this control…

  8. @Ace – This is how browser will render HTML table in case when columns and rows are spanned to one cell. The only trick that might work is to have “hidden” row and column with TD that could not be merged – something with defined X and Y axis. This will ensure that in any moment table will have all cells in one row/column.

  9. @darko thanks for the pointers so far :) i’ve managed to successfully combine your tables and drag scripts so that i can merge and split cells but also drag cloned divs on to these cells this works almost perfect apart from when i merge over 3 columns the drag then stops and i have to split the cells to get it to work again. Is there any way to stop this from happening? also is the any way to fire an event when the table cell is selected? many thanks and great work :)

  10. @Ace – If your table have fixed column number then you can try with colgroup like in Example 24: Table editor. As you can see, no matter of merging cells in a row, row is never streched to the single cell. colgroup defines table columns, here is simple example:

    <colgroup>
        <col width="150"/>
        <col width="150"/>
        <col width="150"/>
        <col width="50"/>
    </colgroup>
    

    And regarding event handlers. Currently, custom event handlers in REDIPS.table lib are not supported. Hope this will be fixed in next release (with some “face lifting” – camelCase syntax and so on). Cheers!

  11. @darko thanks again for the help, I’ve managed to wrap in my own event of sorts, untidy i know but I’m still new to this :) I still have this issue that when i merge 1 col x 4 rows i can no longer drag an element FROM it but can drop TO it if that makes sense?? 1 col x 3 rows is fine but anything over an i have probs. i have uploaded what i have to here if you can have a look at what i mean https://dl.dropboxusercontent.com/u/9432730/eg26/index.html (your browser may have to allow all content – i used IE9 or 10).

    Also can you tell me what section the innerHTML of the cloned div is set so that i can modify it :) many thanks again and this is fantastic coding :)

  12. also darko if you can help – I’ve implemented an ajax call but I lose the clone DIV is there a way to preserve this or re-initialize it?

    thanks again!!

  13. @Ace – I have prepared jsFiddle example that combines REDIPS.drag and REDIPS.table libs. As you can see, after all cells are merged there is no unwanted “strech” effect. colgroup tags defines columns while first hidden column will hold table height. Here is link to the demo:

    http://jsfiddle.net/dbunic/cexn1wvn/

    Table should be re-initialized after cells are merged or splited (see mySplit and myMerge function). This will fix the problem when DIV is placed to one big merged cell.

    I’m not sure what do you mean with “what section the innerHTML of the cloned div is set”. In the cloning process, whole DIV element is cloned and appened to the hidden element on the page. After user releases left mouse button, DIV element will be added to the current TD. Cloned DIV element will have changed only ID. Say, if origin DIV element has id=”a1″, first cloned DIV will have “a1c1”, second “a2c2” and so on.

    You can reference/modify DIV element in REDIPS.event.cloned(clonedElement) event handler. In docs you will find the following info:

    If event handler is called from moveObject() then reference of cloned element is sent as input parameter. Otherwise, reference of cloned DIV element is set to REDIPS.drag.obj while reference of original element is set to REDIPS.drag.objOld public property.

    In your case you can use REDIPS.drag.obj (or rd.obj if rd is set as REDIPS.drag) as reference to the cloned DIV element.

  14. @darko sorry for the delay in writing back got dragged off on another project, this looks perfect i’ll give it a go today and post back, you’re a legend :)

  15. @darko finally got around to implementing your suggestions and works perfectly thanks again. I now have 3 more questions sorry :)

    first, with the generating of the button id, is there any way to have this check to see what is already present in the table, i.e if a table is saved with a div id ac0, ac1 already loaded currently if i drag a new div it will have ac0 as the id on first load.

    second is relating to the split. basically when i initialise my table it currently has a default size of 10×10 and colspan and rowspan set to 2 (so its really 20×20) this is for user friendliness. If i merge 2 cells (actually 4 as far as html code goes) and decide to split them this will give me 2 cells one of rowspan 3 other of rowspan 1 – can i make the split basically try to divide the cell by 2 if the colspan and rowspan are even numbers otherwise revert to the current way if colspan or rowspan are odd numers.

    Last question, how can i tie in to the mouseover event for the drag, basically i would like to add the “mark” css class if a cell already contains a div so that the user cannot drop a div.

    Hope this makes sense :) this is practically the last thing i need for my control to work and thanks again for your fantastic work and continued assistance it is very much appreciated!!

  16. @Ace – Here are answers:

    1)
    Maybe better way is to save id of DIV elements without c0, c1, c2 … to the database. With simple substring function, cut cX part and save origin DIV id. Next, when load from database, append different suffix like ab0, ab1, ab2, ab3 … (b stands for database). With this solution, there will not be a collision between cloned elements and elements from database – the same trick is used in example03 (db_save.php and config.php).

    2)
    Ups, REDIPS.table doesn’t have additional option how to split (2/2 and not 3/1) already merged cells. This will be maybe solved in future releases, sorry.

    3)
    If you want to prevent dropping to already occupied table cells then use “single” drop mode instead of default. After REDIPS.drag initialization just set the following line:

    // elements can be dropped only to the empty table cells
    rd.dropMode = 'single';
    

    Description of all drop modes can be found in documentation. And no problem at all. If you have any other questions, I will gladly try to answer.

  17. Your code is great, thank you. I was wondering if it is possible to use .addClass ?? to a merged cell. I would like to change the background color to cells that are merged. It would make it easier to see where to drop elements. thanks!

  18. Thanks for the great code. Is there a way to re-init the merge function on the cells after an ajax callback?

  19. @jnbridges – REDIPS.table currently doesn’t have option to change color for merged cell. The solution might be to modify REDIPS.table.merge() method to return reference to the newly merged cell. With this update, user will have an option to change background color from JS code where merge() method is called.

    @dduran – It’s possible to call REDIPS.table.onmousedown() method several times or after AJAX call (if needed). omousedown() method simply attaches event listeners to table cells. Here is comment from developer.mozilla.org:

    Multiple identical event listeners
    If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded. They do not cause the EventListener to be called twice, and since the duplicates are discarded, they do not need to be removed manually with the removeEventListener method.

    https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener

  20. Hi, great job.
    I have one question – how to reset selected elements (cells) on table?

Leave a Comment