0

Fiddle here

Basic explanation of the fiddle: When someone starts typing into a cell, then tabs away or unfocuses, it creates a new row above it, blanks out the bottom row, and moves focus to the "next" input element in that new row. It's incomplete, but isolated enough to show the problem behavior.

So I'm having an issue understanding why when I try to go two rows up via previousSibling.previousSibling after going up to the <tr> element via parentElement calls. It hits a text node and thus I cannot reference the child <td> elements. What am I missing?

previousElementSibling cannot be used due to the fact I have to support IE8.

CODE:

<table border="1" cellspacing="1" id="lab-request-data_entry-table">
    <thead class="ui-widget-report-header">
        <tr>
            <th>#</th>
            <th>
                <button class="ui-widget ui-widget-header">Delete</button>
            </th>
            <th>Location</th>
            <th>Barcode</th>
            <th>SumNukm</th>
            <th>Status</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>
                <button class="ui-widget ui-widget-header" onclick="delete_record(this);">Delete</button>
            </td>
            <td>
                <input type="hidden" value="v" />
                <input type="text" value="v" />
            </td>
            <td>
                <input type="hidden" value="222" />
                <input type="text" value="222" />
            </td>
            <td>
                <input type="hidden" value="22" />
                <input type="text" value="22" />
            </td>
            <td>VALID</td>
        </tr>
        <tr>
            <td></td>
            <td></td>
            <td>
                <input type="text" onBlur="add_new_rec(this);" />
            </td>
            <td>
                <input type="text" onBlur="add_new_rec(this);" />
            </td>
            <td>
                <input type="text" onBlur="add_new_rec(this);" />
            </td>
            <td>New Record</td>
        </tr>
    </tbody>
</table>

JS:

add_new_rec = function (obj) {
    var trait_arr = [1, 2, 3];
    var $tbody = $("#lab-request-data_entry-table tbody");
    var $erow = $(obj).parent().parent(); //Entry row.
    var indexCol = $erow.find('td').index($(obj).parent()); //It's index.
    var colCount = $(obj).parent().parent().find('td').length - 3; //Data entry columns to be inserted. Subtract 3 for the number, delete, and status
    var rowLen = $tbody.find("tr").length;
    var row_above = rowLen > 1 ? true : false;
    if ($.trim(obj.value) == '') {
        return;
    }
    var rowInfo = '';
    rowInfo = '<button type="button" class="ui-widget ui-widget-header" onclick="delete_record(this); return false;" >Delete</button>';
    $erow.before('<tr></tr>');
    $erow.prev().append('<td><label>' + (rowLen) + '</label></td><td>' + rowInfo + '</td>');
    //Now iterate through the columns, adding in a previous value if it's not the obj's location
    for (var i = 0; i < colCount; i++) {
        if (i == indexCol - 2) { //Case of it being the row we entered.
            rowInfo = '<td><input type="hidden" value="' + obj.value + '"/><input type="text" value="' + obj.value + '"/></td>';
        } else if (row_above == true) { //If so, pull down the answer into rowinfo
            var numb = i + 2;
            var prevCell = obj.parentElement.parentElement.previousSibling.previousSibling.children[numb].children[0].value; //Due to row added due to row number added already, we have to go another row up.
            rowInfo = '<td><input type="hidden" value="' + prevCell + '"/><input type="text" value="' + prevCell + '"/></td>';
        } else { //Create a blank row element.
            rowInfo = '<td><input type="hidden" value=""/><input type="text" value=""/></td>';
        }
        $erow.prev().append(rowInfo);
    }
    //After done, add a status column with "New Record

    //Call an update function and focus on the "next" row in the new row
    obj.value = '';
};
Orpheus
  • 727
  • 1
  • 7
  • 22
  • once at the tr, use `tr.cells[indexNumber]` to hit any cell in the row by position. probably something like `td.parentNode.parentNode.rows[td.parentNode.rowIndex-1].cells[td.cellIndex]` you might need an extra parentNode in there to handle tbody... – dandavis Sep 16 '15 at 17:40
  • I'm trying to get the value of the cell above it and copy it into the new row. It's a feature request. And by the time I get to that point in execution, there's already a half-done row, so I have to go up two instead of one. – Orpheus Sep 16 '15 at 17:45
  • @Orpheus: Yeah, I'd missed that it was *after* you added a row. – T.J. Crowder Sep 16 '15 at 17:45
  • There's a `previousElementSibling` helper function in [this answer](http://stackoverflow.com/a/5197873/1324) that could get you around this issue, while remaining compatible with older browsers. – Paul Roub Sep 16 '15 at 17:47
  • @PaulRoub: True, but they're *already* using jQuery, so... – T.J. Crowder Sep 16 '15 at 17:48

2 Answers2

3

previousSibling is the previous sibling node, which may well not be an element. This is one of the reasons jQuery exists: The DOM API is a real pain. (Less so these days, on modern browsers we have things like previousElementSibling. But we didn't back when jQuery was created.)

After adding the new row, you can use

$(obj).closest("tr").prev().prev()

...to get the row before the new row. I'd probably do that once, before the loop copying the cell values down, rather than repeatedly in the loop.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
-1

In my case, solution was delete line breaks between HTML elements. Then, previousSibling starting run like a charm.

scamba
  • 1