HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Select row based on another table row index

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
indexanotherbasedselectrowtable

Problem

I have 2 tables. One holds only first column of my "data table" rest is stored in another table, that is placed right to first. What I need to do is to get all the data from specific row to pass it to jqplot.

My tables look like this. My code basically works, but I think it can be improved.

$('table#baseTable  > tbody > tr > td').click(function() {
    var rowIndex = $(this).parent().index();
    $('div#log').html(rowIndex);

    var myData = [];

    $('#dataTable tbody tr:eq(' + rowIndex + ')').map(function() {
            return $(this.cells).get();
        }).each(function() {
    var headerVal = $(this).closest("table").find("thead > tr > th").eq($(this).index()).html();
    myData.push([headerVal, $(this).html()]);
})

    alert(myData);
    console.log(myData);
});​


I'm using this code in ASP page, so that every time I use UpdatePanel I must call my functions again.

This is my plot function:

```
function plot() {
var $plot;
var dataTableRows = $('#Grid3_br tbody tr');

$('td.akcje').on('click', function() {
var $newTitle = $(this).next().text();
var myData = [],
element = $(this),
rowIndex = element.parent().index();

$(dataTableRows[rowIndex]).map(function() {
return $(this.cells).get();
}).each(function(index, value) {
myData.push(['M' + index, parseFloat($(this).html())]);
})
$('#wykres1').empty();//clears old plot. Don't know why re-plotting don't work for me
$plot = $.jqplot('wykres1', [myData], {
title: $newTitle,
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
tickOptions: {
formatString: '%s'
}
},
yaxis: {
tickOptions: {
formatString: '%.2f zł'
}
}
},
highligh

Solution

I'll start with your selectors:

First off, you should never have a selector with anything left of an id - searches for ids are about the fastest you can get on the DOM.

Second, if you don't want to wrap other tables in your tables (I assume you don't), get rid of the immediate child stuff (P > C). Searching by tag is also pretty fast, so we use the id-element as our base for that.

$('#baseTable tbody td').click(function() {
    var rowIndex = $(this).parent().index();
    $('#log').html(rowIndex);

    var myData= [];

    $($('#dataTable tbody tr')[rowIndex]).map(function() {
        return $(this.cells).get();
    }).each(function() {
        var headerVal = $(this).closest('table').find('thead th')
            .eq($(this).index()).html();
        myData.push([headerVal,parseFloat($(this).html())]);
    })

    alert(myData);
    console.dir(myData);
});​


Next, you should cache elements you found, use more than once and which don't change. And usually, it's a bad choice to bind events to the elements directly. I'm assuming jQuery 1.7 is ok and you don't really want to use jQuery 1.4, so we can use on for event binding.

var logDiv = $('#log'),
    dataTableRows = $('#dataTable tbody tr');

$('#baseTable tbody').on('click', 'td', function() {
    var myData = [],
        element = $(this),
        rowIndex = element.parent().index();

    logDiv.html(rowIndex);

    $(dataTableRows[rowIndex]).map(function() {
        return $(this.cells).get();
    }).each(function() {
        var headerVal = $(this).closest('table').find('thead th')
            .eq($(this).index()).html();
        myData.push([headerVal,parseFloat($(this).html())]);
    })

    alert(myData);
    console.dir(myData);
});​


Next, accessing the DOM is rather slow. If you need the data for jqplot, do you need the table headers and can the data change?

Anyway, I'd store all data in an array beforehand. Now it looks like this:

var logDiv = $('#log'),
    dataTable = $('#dataTable'),
    dataTableHeaders = [],
    dataTableData = [];

// cache data table headers
dataTable.find('thead th').each(function(col) {
    dataTableHeaders[col] = $(this).html();
});

// cache full row (including headers) for data table
dataTable.find('tbody tr').each(function(row) {
    var rowData = (dataTableData[row] = []);
    $(this).children().each(function(col) {
        rowData[2 * col] = dataTableHeaders[col];
        rowData[2 * col + 1] = parseFloat($(this).html());
    });
});

// the onClick - but on tr instead of td and with a fast lookup
$('#baseTable tbody').on('click', 'tr', function() {
    var rowIndex = $(this).index(),
        myData = dataTableData[rowIndex];
    logDiv.html(rowIndex);
    alert(myData);
    console.dir(myData);
});​


I still don't like the need for index(). I like it even less than event binding on elements, so I'll compromise:

var logDiv = $('#log'),
    dataTable = $('#dataTable'),
    dataTableHeaders = [],
    dataTableData = [];

dataTable.find('thead th').each(function(col) {
    dataTableHeaders[col] = $(this).html();
});

dataTable.find('tbody tr').each(function(row) {
    var rowData = (dataTableData[row] = []);
    $(this).children().each(function(col) {
        rowData[2 * col] = dataTableHeaders[col];
        rowData[2 * col + 1] = parseFloat($(this).html());
    });
});

$('#baseTable tbody tr').each(function(row) {
    $(this).on('click', function() {
        var data = dataTableData[row];
        logDiv.html(row);
        alert(data);
        console.dir(data);
    });
});


​Here's my last step (this is not really needed, but I like it): we isolate this code from the outside world and make accidental messups a lot harder. And we enable a recalculation and rebinding of the click event if anything changes (number of rows / cols or the content).

```
var tableData = (function(){
var logDiv = $('#log'),
cacheRows = function() {
var dataTable = $('#dataTable'),
dataTableHeaders = [],
dataTableData = [];
// fetch headers
dataTable.find('thead th').each(function(col) {
dataTableHeaders[col] = $(this).html();
});
// fetch column data, prepare row arrays
dataTable.find('tbody tr').each(function(row) {
var rowData = (dataTableData[row] = []);
$(this).children().each(function(col) {
rowData[2 * col] = dataTableHeaders[col];
rowData[2 * col + 1] = parseFloat($(this).html());
});
});
// return row arrays
return dataTableData;
},
bindOnClick = function() {
var dataTableData = cacheRows();
$('#baseTable tbody tr').each(function(row) {
$(this).on('click', function() {
var data = dataTableData[row];
logDiv.html(row);
alert(data)

Code Snippets

$('#baseTable tbody td').click(function() {
    var rowIndex = $(this).parent().index();
    $('#log').html(rowIndex);

    var myData= [];

    $($('#dataTable tbody tr')[rowIndex]).map(function() {
        return $(this.cells).get();
    }).each(function() {
        var headerVal = $(this).closest('table').find('thead th')
            .eq($(this).index()).html();
        myData.push([headerVal,parseFloat($(this).html())]);
    })

    alert(myData);
    console.dir(myData);
});​
var logDiv = $('#log'),
    dataTableRows = $('#dataTable tbody tr');

$('#baseTable tbody').on('click', 'td', function() {
    var myData = [],
        element = $(this),
        rowIndex = element.parent().index();

    logDiv.html(rowIndex);

    $(dataTableRows[rowIndex]).map(function() {
        return $(this.cells).get();
    }).each(function() {
        var headerVal = $(this).closest('table').find('thead th')
            .eq($(this).index()).html();
        myData.push([headerVal,parseFloat($(this).html())]);
    })

    alert(myData);
    console.dir(myData);
});​
var logDiv = $('#log'),
    dataTable = $('#dataTable'),
    dataTableHeaders = [],
    dataTableData = [];

// cache data table headers
dataTable.find('thead th').each(function(col) {
    dataTableHeaders[col] = $(this).html();
});

// cache full row (including headers) for data table
dataTable.find('tbody tr').each(function(row) {
    var rowData = (dataTableData[row] = []);
    $(this).children().each(function(col) {
        rowData[2 * col] = dataTableHeaders[col];
        rowData[2 * col + 1] = parseFloat($(this).html());
    });
});

// the onClick - but on tr instead of td and with a fast lookup
$('#baseTable tbody').on('click', 'tr', function() {
    var rowIndex = $(this).index(),
        myData = dataTableData[rowIndex];
    logDiv.html(rowIndex);
    alert(myData);
    console.dir(myData);
});​
var logDiv = $('#log'),
    dataTable = $('#dataTable'),
    dataTableHeaders = [],
    dataTableData = [];

dataTable.find('thead th').each(function(col) {
    dataTableHeaders[col] = $(this).html();
});

dataTable.find('tbody tr').each(function(row) {
    var rowData = (dataTableData[row] = []);
    $(this).children().each(function(col) {
        rowData[2 * col] = dataTableHeaders[col];
        rowData[2 * col + 1] = parseFloat($(this).html());
    });
});

$('#baseTable tbody tr').each(function(row) {
    $(this).on('click', function() {
        var data = dataTableData[row];
        logDiv.html(row);
        alert(data);
        console.dir(data);
    });
});
var tableData = (function(){
    var logDiv = $('#log'),
        cacheRows = function() {
            var dataTable = $('#dataTable'),
                dataTableHeaders = [],
                dataTableData = [];
            // fetch headers
            dataTable.find('thead th').each(function(col) {
                dataTableHeaders[col] = $(this).html();
            });
            // fetch column data, prepare row arrays
            dataTable.find('tbody tr').each(function(row) {
                var rowData = (dataTableData[row] = []);
                $(this).children().each(function(col) {
                    rowData[2 * col] = dataTableHeaders[col];
                    rowData[2 * col + 1] = parseFloat($(this).html());
                });
            });
            // return row arrays
            return dataTableData;
        },
        bindOnClick = function() {
            var dataTableData = cacheRows();
            $('#baseTable tbody tr').each(function(row) {
                $(this).on('click', function() {
                    var data = dataTableData[row];
                    logDiv.html(row);
                    alert(data);
                    console.dir(data);
                });
            });
        };
    bindOnClick();
    return {
        refresh: bindOnClick
    };
})();

Context

StackExchange Code Review Q#14295, answer score: 9

Revisions (0)

No revisions yet.