1
votes

I have created a Table Chart according to Google's Visualization API and published the web app here. The data source is a Google Spreadsheet with Google Form responses. A couple columns contain a list of comma separated values, which are responses of the form's Checklist items. I have applied a "CategoryFilter" to these columns. However, instead of individualizing each comma separated value it treats it as one value.

Image of CSV Values not Separated

I would like for the filter to separate the values based on the comma and then stack them in a dropdown list. Is there a way to do this?

I have tried creating the values according to the API for the values for the "Grade Level(s)" filter, but when I choose one of the values in the filter it finds no result (I assume because the CategoryFilter does not do partial matches).

 var gradeLevels = ['K-2','3-5'];

   var GradeLevelCategoryFilter = new google.visualization.ControlWrapper({
      'controlType': 'CategoryFilter',
      'containerId': 'GradeLevelCategoryFilter',
      'options': {
       'filterColumnIndex': '11',
       'matchType': 'any',
       'allowTyping': true,
       'values' : gradeLevels,
       'ui': {
       'labelStacking': 'horizontal',
       'label': '',
       'caption' : 'Filter by Grade Level(s)',
       'selectedValuesLayout': 'aside',
       'sortValues' : false,
       }
      }
    });  
1
you would need to manually fill the values property, as you have done, from all the rows in the table -- you would also need to unbind and handle the filter manually on the 'statechange' eventWhiteHat
Thank you for the response, WhiteHat. I really appreciate it! I am at a loss of how to do the manual filter, however. Would I still use a CategoryFilter? I have created a JSFiddle hoping you can provide me a little more direction. linkJerry Williamson
I adapted code from Cyberliving.com to that does not bind the filter to the table, but manually filter the data via query. However, I do not know how to "combine" the filters. For instance, if I choose K-2 in the filter, that filter is overridden when I click on 3-5. I need to stack them. And then if I create a filter for subject areas, I need to stack them with the grade levels. Here is a JS Fiddle using a manual checkbox filter (jsfiddle.net/jerryawilliamson/9stvza73/…)Jerry Williamson

1 Answers

1
votes

when the spreadsheet loads,
use data table method getDistinctValues(index) on the column
this will return a distinct list of the column values
then split each value on comma and build a unique list of the choices
use the choices for the values option on the filter

then on the filter's 'statechange' event,
use data table method getFilteredRows() to find the row indexes
which contain the filter's selected choice(s)
use the row indexes to set a view on the chart

see following working snippet, a table chart is used...

google.charts.load('current', {
  packages:['controls', 'corechart', 'table']
}).then(function () {
  var sheet = 'https://docs.google.com/spreadsheets/d/1DOTezFuzpH8wzeh25Cgv9e9q577zd_HN1TiIxVQzbUQ/edit#gid=0';

  var table = new google.visualization.ChartWrapper({
    chartType: 'Table',
    containerId: 'chart-table',
    options: {
      allowHtml: true
    }
  });

  var filter = new google.visualization.ControlWrapper({
    controlType: 'CategoryFilter',
    containerId: 'filter-grade',
    options: {
      filterColumnIndex: 12,
      matchType: 'any',
      allowTyping: true,
      ui: {
        labelStacking: 'horizontal',
        label: '',
        caption: 'Filter by Grade Level(s)',
        selectedValuesLayout: 'aside',
        sortValues: false
      }
    }
  });

  new google.visualization.Query(sheet).send(function (response) {
    var data = response.getDataTable();
    var gradeAnswers = data.getDistinctValues(12);
    var gradeChoices = [];
    gradeAnswers.forEach(function (answer) {
      if (answer !== null) {
        var choices = answer.split(',');
        choices.forEach(function (choice) {
          choice = choice.trim();
          if (gradeChoices.indexOf(choice) === -1) {
            gradeChoices.push(choice);
          }
        });
      }
    });
    gradeChoices.sort();

    google.visualization.events.addListener(filter, 'statechange', function () {
      var state = filter.getState().selectedValues;
      table.setView(null);
      if (state.length > 0) {
        table.setView({
          rows: data.getFilteredRows([{
            column: 12,
            test: function (value) {
              var found = false;
              if (value !== null) {
                state.forEach(function (selected) {
                  if (value.indexOf(selected) > -1) {
                    found = true;
                  }
                });
              }
              return found;
            }
          }])
        });
      }
      table.draw();
    });

    filter.setDataTable(data);
    filter.setOption('values', gradeChoices);
    filter.draw();
    table.setDataTable(data);
    table.draw();
  });
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="filter-grade"></div>
<div id="chart-table"></div>

EDIT

you can set the view on the initial definition...

var table = new google.visualization.ChartWrapper({
  chartType: 'Table',
  containerId: 'chart-table',
  options: {
    allowHtml: true
  },
  view: {
    columns: [0]
  }
});

or use the setView method...

table.setView({
  columns: [0]
});

EDIT 2

  var view = {
    columns: [0]
  };
  if (state.length > 0) {
    view.rows = data.getFilteredRows([{
      column: 12,
      test: function (value) {
        var found = false;
        if (value !== null) {
          state.forEach(function (selected) {
            if (value.indexOf(selected) > -1) {
              found = true;
            }
          });
        }
        return found;
      }
    }]);
  }
  table.setView(view);

EDIT 3

you can combine multiple filters into an array,
before passing to getFilteredRows

var view = {
  columns: [0]
};
var viewFilters = [];
if (stateGrade.length > 0) {
  viewFilters.push({
    column: 12,
    test: function (value) {
      var found = false;
      if (value !== null) {
        stateGrade.forEach(function (selected) {
          if (value.indexOf(selected) > -1) {
            found = true;
          }
        });
      }
      return found;
    }
  });
}
if (stateSubject.length > 0) {
  viewFilters.push({
    column: subjectIndex,
    test: function (value) {
      var found = false;
      if (value !== null) {
        stateSubject.forEach(function (selected) {
          if (value.indexOf(selected) > -1) {
            found = true;
          }
        });
      }
      return found;
    }
  });
}
view.rows = data.getFilteredRows(viewFilters);
table.setView(view);