Google visualization data.join创建的dataTable的dataView的chartWrapper在值更改时不更新

Google visualization data.join创建的dataTable的dataView的chartWrapper在值更改时不更新,google-visualization,Google Visualization,首先,请原谅下面的小说,但这很难描述 我有一个相当复杂的应用程序,我目前正在通过一个GAS应用程序的HtmlService使用gviz 不过,这更像是一个客户端gviz API问题 我正在通过query方法加载两个数据表,并通过data.join将它们组合起来。该结果数据表是数据视图的源 然后使用该视图生成具有多个类别过滤器和单个tableChart的仪表板。我有一个按钮,可以在显示的视图行和列的两个过滤器集之间切换。其概念是加载所有记录,并在挂起和完成之间切换,向用户显示相关列 这部分实际上工

首先,请原谅下面的小说,但这很难描述

我有一个相当复杂的应用程序,我目前正在通过一个GAS应用程序的HtmlService使用gviz

不过,这更像是一个客户端gviz API问题

我正在通过query方法加载两个数据表,并通过data.join将它们组合起来。该结果数据表是数据视图的源

然后使用该视图生成具有多个类别过滤器和单个tableChart的仪表板。我有一个按钮,可以在显示的视图行和列的两个过滤器集之间切换。其概念是加载所有记录,并在挂起和完成之间切换,向用户显示相关列

这部分实际上工作得非常好。我遇到的问题是数据更新问题。每次可视化绘制时,我都会遍历生成的表,并将操作附加到各个列

一个这样的操作打开一个带有行值的jQueryUI对话框,允许用户进行修改并提交到服务器。当它提交时,而不是重新查询我的数据,我的方法是在ajaxsuccess上更新dataTable,这要快得多

在实现连接之前,这是基于单个dataTable的,当我更新dataTable时,基于它的dataView也会更新,在chartWrapper上调用draw()会按照预期更新UI

问题是,这在联接的数据表上不起作用。我已经在客户端的开发者工具中确认,dataTable实际上正在像dataView一样更新值,但这不会传播到tableChart

这是真正奇怪的部分。如果在开发工具中使用chartWrapper的.getDataTable方法,我可以确认有问题的记录已更新尽管生成的可视化中的值不是

我尝试在AJAX成功中重新绘制图表包装器,但没有成功。当滚动级别更改时,它会重新绘制(chartWrapper),但数据不会更改。我尝试在开发工具中手动重画chartWrapper和dashboard,甚至将视图作为dataTable传递。事实上,两者都会重新绘制,但都不会更新数据

我曾尝试在chartWrapper上重新绘制getDataTable表,但这基本上与我的仪表板和样式分离,并绘制了整个数据集,这不是我所需要的

更改类别筛选器不会在回筛选后更新tableChart。即使将不同的过滤器应用到dataView,然后再返回,也不会更新它。我发现唯一有效的方法是重新查询整个内容,这需要5-10秒的时间。每一次变更都是不可接受的延误。在第一次加载时,这很好,但理想情况下,每个用户会话只发生一次

我花了数小时调试和整理(糟糕的)文档,我看到的一切似乎都表明它应该可以工作

我开始怀疑这可能是某种缓存问题,还是我遗漏了一些文档中没有解释的技巧

这个特定页面的客户端代码是1100行,所以很难完整发布。下面是一个非常简单的版本,我正在做的关键部分包括。如有任何意见或建议,将不胜感激

注意,我省略了许多与生成操作的对话框或按钮相关的部分,但它们大多是不相关的

var loaded = false;
var ready = {pro: false, sec: false};
var data = {};

    // Ajax load gviz api
    $.ajax({
      url: 'https://www.google.com/jsapi?callback',
      cache: true,
      dataType: 'script',
      success: function(){
            google.load('visualization', '1', {packages:['controls'], 'callback' : sendQuery
        });
        return true;
      }
    });
    function sendQuery() {
        console.log('query setting');
        var opts = {sendMethod: 'auto'};

        var urlPro = 'Google Spreadsheet source 1';
        queryPro = new google.visualization.Query(urlPro, opts);
        queryPro.setQuery('select A,B,C,D,E where(G = \'No\')');//...15k+ rows 30+ cols in reality

        var urlSec = 'Google Spreadsheet source 2';
        querySec = new google.visualization.Query(urlSec, opts);
        querySec.setQuery('select A,B,C,D');//...~200+ rows 30+ cols in reality, rows created with app

        queryPro.send(function(response){
            console.log('query Pro returned');
            if (response.isError()) {
                alert('Error in query Pro: ' + response.getMessage() + ' ' + response.getDetailedMessage());
                return;
            }
            ready.pro = true;
            data.pro = response.getDataTable();
            if (ready.pro && ready.sec) {
                drawDashboard(false);
            }
        });
        querySec.send(function(response){
            if (response.isError()) {
                alert('Error in query Sec: ' + response.getMessage() + ' ' + response.getDetailedMessage());
                return;
            }
            console.log('query Sec returned');
            ready.sec = true;
            data.sec = response.getDataTable();
            if (ready.pro && ready.sec) {
                drawDashboard(false);
            }
        });

    }

    function drawDashboard(complete) {
      var pendingCols = [0,2,3,4];
      var completeCols = [1,2,3,4,5,7,8];

      if (!loaded) {
          console.log('first load of data');

          var joinProCols=[1,2,3,4];
          var joinSecCols=[1,2,3];

          joined = new google.visualization.data.join(data.pro, data.sec, 'left', [[0, 0]], joinProCols, joinSecCols);

          viewActive = new google.visualization.DataView(joined);

          var numCols = joined.getNumberOfColumns();
          for (var i=0; i<numCols; i++){
            ogColName = joined.getColumnLabel(i).replace(/\W/g, '');
            if (empTable.hasOwnProperty(ogColName)){ //passed from server; ommitted def in this example
                joined.setColumnLabel(i, empTable[ogColName][lang]);
            }
            joined.setColumnProperty(i, 'ident', ogColName);
          }

      }

      var pendingRows = joined.getFilteredRows([{column: 4, value: null}]);
      var completeRows = joined.getFilteredRows([{column: 4, minValue: ''}]);

      if (complete) {
          viewActive.setColumns(completeCols);
          viewActive.setRows(completeRows);
      } else {
          viewActive.setColumns(pendingCols);
          viewActive.setRows(pendingRows);
      }

      dashboard = new google.visualization.Dashboard(document.getElementById('dashboard-div'));

      // options for displayed table
      var tableOpts = { 
        width: '1500px',
        height: '100%', 
        page: 'enable', 
        pageSize: 40,
        cssClassNames: {
          headerCell: 'gviz header',
          headerRow: 'gviz header',
          oddTableRow: 'gviz odd',
          tableRow: 'gviz even',
          selectedTableRow: 'gviz selected',
          hoverTableRow: 'gviz hover',
          rowNumberCell: 'gviz rowNum'
        }
      };

      tableChart = new google.visualization.ChartWrapper({
        'chartType': 'Table',
        'containerId': 'table-div',
        'options': tableOpts
      });

      var picker1 = new google.visualization.ControlWrapper({
          'controlType': 'CategoryFilter',
          'containerId': 'sel-pick1',
          'options': {
            'filterColumnLabel': 'Picker1',
            'ui': {
              'labelStacking': 'vertical',
              'selectedValuesLayout': 'belowWrapping',
              'caption': 'Picker1'
            }
          }
        });
      var picker2 = new google.visualization.ControlWrapper({
          'controlType': 'CategoryFilter',
          'containerId': 'sel-pick2',
          'options': {
            'filterColumnLabel': 'Picker2',
            'ui': {
              'labelStacking': 'vertical',
              'selectedValuesLayout': 'belowWrapping',
              'caption': 'Picker2'
            }
          }
        });
      //...quite a few more pickers in real code
      if (complete) {

          var picker3 = new google.visualization.ControlWrapper({
            'controlType': 'CategoryFilter',
            'containerId': 'sel-pick3',
            'options': {
              'filterColumnLabel': 'picker3',
              'ui': {
                'labelStacking': 'vertical',
                'selectedValuesLayout': 'belowWrapping',
                'caption': 'picker3'
              }
            }
          });
          //...A couple more pickers in real app here too
      }
      // Set up dependencies between controls and charts
      dashboard.bind(picker1, picker2);
      //...bindings for other pickers
      if (complete) {
          dashboard.bind(picker2, picker3);
          dashboard.bind([picker1, picker2, picker3], tableChart);
      } else {
          dashboard.bind([picker1, picker2], tableChart);
      }
      // Draw all visualization components of the dashboard and add listeners

      google.visualization.events.addListener(tableChart, 'ready', function(){
        google.visualization.events.addListener(tableChart.getChart(), 'page', addFields);
        google.visualization.events.addListener(tableChart.getChart(), 'sort', addFields);
        google.visualization.events.addListener(tableChart.getChart(), 'select', function(e){
            //cancel selection here as it won't be useful
            tableChart.getChart().setSelection('');
        });
        //grab the table and inject our custom actions into it
        if (complete) {
            addFields(true);
        } else {
            addFields();
        }
        // show containers
        $('.processing.page').hide();
        $('#dashboard-div').show();
        loaded = true;

      });


      dashboard.draw(viewActive);


  }

  //........................................

  $('#dataForm').submit(function( event ) {
            if ($('#dataForm').valid()){
                $('#dataForm').hide();
                $('.processing.data.form').show();
                google.script.run.withSuccessHandler(onSuccessUpdate).recordData(this);
            }
            event.preventDefault();
    });
    //...................................................
    function onSuccessUpdate(response){
      var numCols = joined.getNumberOfColumns();
      for (var i=0; i<numCols; i++){
          for (var key in response.form){
            if (!response.form.hasOwnProperty(key)) continue;
            if (joined.getColumnProperty(i, 'ident') == key){
                joined.setValue(response.row, i, response.form[key]);
            }
          }
      }
      tableChart.draw();//This should be updating the values!
      $('.message.success').html(response.message).show();
      $('#dataForm').show();
      $('.processing.data.form').hide();
      $('#userProfileDialog').dialog('close');
  }
var-load=false;
var ready={pro:false,sec:false};
变量数据={};
//Ajax加载gviz-api
$.ajax({
网址:'https://www.google.com/jsapi?callback',
是的,
数据类型:“脚本”,
成功:函数(){
load('visualization','1',{packages:['controls'],'callback':sendQuery
});
返回true;
}
});
函数sendQuery(){
log(“查询设置”);
var opts={sendMethod:'auto'};
var urlPro='谷歌电子表格源1';
queryPro=newgoogle.visualization.Query(urlPro,opts);
setQuery('selecta,B,C,D,E其中(G=\'No\');/…15k+行30+列
var urlSec='谷歌电子表格源2';
querySec=newgoogle.visualization.Query(urlSec,opts);
setQuery('select A,B,C,D');/…~200+行30+列实际上是用app创建的行
queryPro.send(函数(响应){
log('query Pro returned');
if(response.isError()){
警报('query Pro中的错误:'+response.getMessage()+'+response.getDetailedMessage());
返回;
}
ready.pro=true;
data.pro=response.getDataTable();
if(ready.pro&&ready.sec){
drawDashboard(假);
}
});
querySec.send(函数(响应){
if(response.isError()){
警报('query Sec中的错误:'+response.getMessage()+'+response.getDetailedMessage());
返回;
}
log('query Sec returned');
ready.sec=true;
data.sec=response.getDataTable();
if(ready.pro&&ready.sec){
drawDashboard(假);
}
});
}
功能面板(完整){
var pendingCols=[0,2,3,4];
var completeCols=[1,2,3,4,5,7,8];
如果(!已加载){
log(“第一次加载数据”);
var joinProCols=[1,2,3,4];
var joinSecCols=[1,2,3];
join=new google.visualization.data.join(data.pro,data.sec,'left',[[0,0]],joinProCols,joinSecCols);
viewActive=新的google.visualization.DataView(已加入);
var numCols=joined.getNumberOfColumns();
法罗群岛
function onSuccessUpdate(response){
      var numCols = joined.getNumberOfColumns();
      for (var i=0; i<numCols; i++){
          for (var key in response.form){
            if (!response.form.hasOwnProperty(key)) continue;
            if (joined.getColumnProperty(i, 'ident') == key){
                joined.setValue(response.row, i, response.form[key]);
                //Need to also set formatted value
                joined.setFormattedValue(response.row, i, response.form[key]);
            }
          }
      }
      tableChart.draw();//This should be updating the values!
      $('.message.success').html(response.message).show();
      $('#dataForm').show();
      $('.processing.data.form').hide();
      $('#userProfileDialog').dialog('close');