首先請原諒下面的小說,但這很難描述。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');
}
在此先感謝您的任何見解。這個讓我瘋狂。
也許chartWrapper具有正確的dataTable/dataView引用,但由於某種原因沒有註冊該更改。也許嘗試'chartWrapper.getChart()。draw(chartWrapper.getDataTable(),options)'?我的單線測試沒有經過測試,但我認爲您會明白... – nbering
或者您可能需要重新繪製儀表板而不是圖表? – nbering
@nbering既不可行。兩者都會觸發重繪,但即使更新了dataTables和dataView中的所有值,顯示的值本身仍保持不變。 – Marcin