2016-06-24 45 views
1

首先請原諒下面的小說,但這很難描述。chartViewData of dataView由data.join創建而不是更新值更改

我有一個相當複雜的應用程序,目前正在使用gviz通過HASService的GAS應用程序。

雖然這是更多的客戶端gviz API問題。

我正在通過查詢方法加載2個數據表並通過data.join進行組合。這個結果dataTable是數據視圖的來源。

該視圖然後用於生成具有多個類別過濾器和單個tableChart的儀表板。我有一個按鈕可以在顯示的視圖行和列中的兩個過濾器組之間切換。這個概念是加載所有記錄並在掛起和完成之間切換,向用戶顯示相關列。

這部分實際上工作得很好。我遇到的問題是數據更新問題。每次可視化繪製時,我遍歷結果表並將操作附加到各個列。

一個這樣的動作用行值打開一個jQueryUI對話框,並允許用戶進行修改並提交給服務器。當它提交時,我的方法是更新AJAX成功的dataTable,而不是重新查詢我的數據,這要快得多。

在實現連接之前,這是基於單個數據表的,當我更新dataTable時,基於它的dataView也會更新,並且在chartWrapper上調用draw()將會按照預期更新UI。

問題是,這不適用於加入的dataTable。我已經在客戶端的開發人員工具中確認dataTable實際上更新了dataView的值,但是這絕不會傳播到tableChart。

這裏是真正奇怪的部分。如果在開發工具中使用chartWrapper的.getDataTable方法,我可以確認有問題的記錄已更新!儘管生成的可視化文件中的值不是

我試過在我的AJAX成功中重繪chartWrapper無濟於事。它會在滾動級別更改時重繪(chartWrapper),但數據不會更改。我已經嘗試在dev工具中手動重繪chartWrapper和儀表板,甚至將視圖作爲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'); 
    } 

在此先感謝您的任何見解。這個讓我瘋狂。

+0

也許chartWrapper具有正確的dataTable/dataView引用,但由於某種原因沒有註冊該更改。也許嘗試'chartWrapper.getChart()。draw(chartWrapper.getDataTable(),options)'?我的單線測試沒有經過測試,但我認爲您會明白... – nbering

+0

或者您可能需要重新繪製儀表板而不是圖表? – nbering

+0

@nbering既不可行。兩者都會觸發重繪,但即使更新了dataTables和dataView中的所有值,顯示的值本身仍保持不變。 – Marcin

回答

1

事實證明,所有事情都是按照應有的方式工作的,事實上,我錯過了這種工作方式的關鍵方面。

當在循環更新接合的dataTable值,我正在更新的「價值」使用的setValue()方法。

然而,「值」,該呈現圖表實際讀取的是「格式化的值」通過setFormattedValue()方法進行訪問。以編程方式更新該值時,似乎沒有對formattedValue進行自動更新。我可能錯誤地認爲,或者更可能是因爲我沒有使用它而對它的那部分完全無知。

原來,之前使用的時候我只用一個單一的數據源和所有正在,我經過參數「選項no_format」到查詢的連接。在這種情況下,API似乎會使用該值而不是實際表格的formattedValue。

一旦我意識到自己的錯誤,我在修復的第一次嘗試是「no_format選擇」參數添加到我的兩個數據的查詢。這似乎沒有工作。它看起來像連接方法自動生成格式化的值,即使它的源數據表沒有任何。

因此,校正到我的原始代碼是使用setFormattedValue方法除了setValues方法方法如下:

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'); 

一旦兩個值和格式化的值被更新時,如預期的圖表更新在平局。

所以最終,這只是我的一個錯誤,但我希望有可能是一些價值,有人用這個例子的代碼,並通過連接方法所產生的DataTable的這一特定行爲。

相關問題