How to obtain correct google.visualization.Table#selection row index when using ControlWrapper for filtering?

StackOverflow https://stackoverflow.com/questions/23576247

  •  19-07-2023
  •  | 
  •  

سؤال

The following works fine (see jsfiddle) except when the table is filtered via one of the control wrappers. It seems that currentRow and rowIndex always have the same number e.g. google.visualization.DataView#getTableRowIndex(currentRow) doesn't do any translation; it simply spits out the same number that's passed in. How must the row index be properly translated so that one can obtain the desired row from the underlying google.visualization.DataTable?

function drawChart()
{
    var dataTable = new google.visualization.DataTable();
    dataTable.addColumn('date', 'Request Date');
    dataTable.addColumn('string', 'To Do');
    dataTable.addColumn('date', 'Target Complete Date');
    dataTable.addColumn('number', 'Duration');
    dataTable.addColumn('date', 'Date Completed');
    dataTable.addColumn('number', 'ID');

    dataTable.addRow([
        new Date(2014, 1, 24),
        'To do item 1',
        new Date(2014, 1, 27),
        3.5,
        new Date(2014, 1, 26),
        1000
    ]);

    dataTable.addRow([
        new Date(2014, 2, 24),
        'To do item 2',
        new Date(2014, 2, 27),
        1.5,
        new Date(2014, 2, 26),
        1001
    ]);

    dataTable.addRow([
        new Date(2014, 3, 24),
        'To do item 3',
        new Date(2014, 3, 27),
        7.5,
        new Date(2014, 3, 26),
        1002
    ]);

    dataTable.addRow([
        new Date(2014, 4, 24),
        'To do item 4',
        new Date(2014, 4, 27),
        4.5,
        new Date(2014, 4, 26),
        1003
    ]);

    dataTable.addRow([
        new Date(2014, 5, 24),
        'To do item 5',
        new Date(2014, 5, 27),
        2.5,
        new Date(2014, 5, 26),
        1004
    ]);

    //  Format the duration column so that it shows two decimal places.
    var durationFormatter = new google.visualization.NumberFormat({ 'fractionDigits': 2 });
    durationFormatter.format(dataTable, 3);     // Apply formatter to duration column

    //  Table chart
    var cssClassNames = {
        'headerRow': 'dataHeaderRow',
        'tableRow': 'dataTableRow',
        'oddTableRow': 'dataOddTableRow',
        'selectedTableRow': 'dataSelectedTableRow',
        'hoverTableRow': 'dataHoverTableRow',
        'headerCell': 'dataHeaderCell',
        'tableCell': 'dataTableCell',
        'rowNumberCell': 'dataRowNumberCell'
    };

    var tableChartOptions = {
        'cssClassNames': cssClassNames,
        'alternatingRowStyle': true,
        'page': 'enable',
        'pageSize': 10,
        'pagingSymbols': {
            prev: '<span class="fa fa-arrow-left"></span>',
            next: '<span class="fa fa-arrow-right"></span>'
        },
        'pagingButtonsConfiguration': 'auto',
        'sort': 'enable',
        'sortAscending': true,
        'sortColumn': 0,      //  <-- Initially sort by column 0: date column.
        'title': 'Completed To Do List',
        'width': '100%'
    };

    // Prevent the database ID (column 5 in underlying data table) from being 
    // displayed via a data view.
    var rawDataView_NoID = new google.visualization.DataView(dataTable);        
    rawDataView_NoID.setColumns([0, 1, 2, 3, 4]);

    var chartWrapper = new google.visualization.ChartWrapper({
        'chartType': 'Table',                            //  <-- google.visualization.Table
        'containerId': 'loggedInCompletedToDoChart_div',
        'options': tableChartOptions
    } );

    //  The chart must be ready before the select listener can be created.
    google.visualization.events.addListener(
        chartWrapper,
        'ready',
        function () {
            var visualization_table = chartWrapper.getChart();  //  <-- google.visualization.Table
            google.visualization.events.addListener(
                visualization_table,
                'select',
                function () {
                    //  Chart wrapper in this case is configured to allow only
                    //  a single row selection. Hence, an array of length 1.
                    var selection = visualization_table.getSelection()[0];
                    var currentRow, rowIndex, duration, entryId;
                    if (selection !== undefined) {
                        currentRow = selection.row;
                        rowIndex = chartWrapper.getDataTable().getTableRowIndex(currentRow);
                        duration = dataTable.getFormattedValue(rowIndex, 3); 

                        // entryId is available in underlying data table -- not in data view.
                        entryId = dataTable.getFormattedValue(rowIndex, 5);
                        alert(entryId); // Only correct when no filtering takes place.
                    }
                }
    );});

    // Define Filter controls
    var toDoFilter = new google.visualization.ControlWrapper({
        'controlType': 'StringFilter',
        'containerId': 'loggedInCompletedToDo_ToDo_SearchInputElement_div',
        'options': {
            'filterColumnLabel': 'To Do',
            'matchType': 'any'
    }});

    var durationFilter = new google.visualization.ControlWrapper({
        'controlType': 'NumberRangeFilter',
        'containerId': 'loggedInCompletedToDo_Duration_SearchInputElement_div',
        'options': {
            'filterColumnLabel': 'Duration',
            'ui': {
                'format': { 'fractionDigits': 2 },
                'step': 0.25
            }
    } } );

    // Create the dashboard.
    var dashboard = new google.visualization.Dashboard(
        document.getElementById('loggedInCompletedToDoDashboard_div')
    ).
    // Configure the filters to affect the chart content
    bind([ toDoFilter, durationFilter ], chartWrapper).
    // Draw the dashboard
    draw(rawDataView_NoID);
}

google.load('visualization', '1.0', {packages: ['table', 'controls']});
google.setOnLoadCallback(drawChart);

EDIT:

I've noticed that the problem only occurs with the first control wrapper passed to the bind function. In other words with the following configuration the row selection stops working correctly if the To Do filter is used:

    bind([ toDoFilter, durationFilter ], chartWrapper).

and if I swap the order of the filters then the row selection stops working correctly if the Duration filter is used:

    bind([ durationFilter, toDoFilter ], chartWrapper).

If I chain the method invocations as follows the first control wrapper object in the chain is the one that causes row selection to not work properly (just as the first control wrapper object in the array, above, did) and, worse, doing it this way causes the select handler to be invoked 14 times in a row with a single click of the mouse:

    bind(durationFilter, chartWrapper).
    bind(toDoFilter, chartWrapper).

According to the API reference:

bind(controls, charts)

Binds one or more Controls to one or more other dashboard participants (either charts or other controls), so that all of the latter are redrawn whenever any of the former collects a programmatic or user interaction that affects the data managed by the dashboard. Returns the dashboard instance itself for chaining multiple bind() calls together.

controls - Either a single one or an array of google.visualization.ControlWrapper instances defining the controls to bind.

charts - Either a single one or an array of google.visualization.ChartWrapper instances defining the charts the that will be driven the by the controls.

هل كانت مفيدة؟

المحلول

You can avoid this by just referencing the data passed to the ChartWrapper instead of trying to translate back to the original DataTable. Change this:

currentRow = selection.row;
rowIndex = chartWrapper.getDataTable().getTableRowIndex(currentRow);
duration = dataTable.getFormattedValue(rowIndex, 3);

to this:

duration = chartWrapper.getDataTable().getFormattedValue(selection.row, 3);

Also, ChartWrappers now support the "select" event natively, so you don't need to wrap them with a "ready" event:

google.visualization.events.addListener(chartWrapper, 'select', function () {
    // selection handling
});
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top