我有一个谷歌工作表,我正在为我的团队正在进行的项目使用数据库。我想做的是使用这些数据在谷歌网站上构建不同的屏幕。例如,我已经能够添加一个显示所有活动项目的下拉列表。选择项目后,将返回并显示一个HTML表。
现在,我要添加的是一个甘特图到客户端HTML中,数据来自同一个谷歌工作表。我从展示团队的能力中推断了很多,并将gviz文档用作图表信息的资源。我的大部分代码运行良好,但我在将图表数据从Sheets端发送到客户端HTML时遇到了问题。
在我的图表构建代码中,我有一个Logger.log
语句,它表明chartData
是Array
,并且它具有我期望的数据:
function buildChart(project) {
var detailsSheet = ss.getSheetByName("Details");
var details = detailsSheet.getRange(2, 1, detailsSheet.getLastRow(), detailsSheet.getLastColumn()).getValues();
// get the list of teams working on the selected project
var teams = getTeamsFromProjects(project, details); // Works, not shown.
// get the list of teams, without the category
var sendTeams = new Array();
for (l in teams) {
var lRow = teams[l];
sendTeams.push(lRow[0]);
}
// get the projects that the teams are working on
var projectList = getProjectsFromTeams(sendTeams, details); // Works, not shown.
var chartData = getChartDataFromProjects(projectList, details); // Works, not shown.
Logger.log(chartData); // this shows that my data is there, in an array
return chartData;
}
在Web应用程序的HTML中,我有一个console.log("HTML: " + HTML)
,它正确地显示了返回的HTML(来自.gs函数displayTeams()
,它看起来是正确的。在HTML中,还有一个console.log("chart data: " + chartData)
,它应该显示返回的数组。然而,控制台显示chartData
为NULL。
我的问题是,当我可以从Apps ScriptLogger.log()
语句(就在返回之前)中看到数据正确地是数组时,为什么chartData
会被返回(或至少写入到Web应用程序的控制台日志中)为NULL?
我的一些相关HTML文件:
<!DOCTYPE html>
<html>
<style>
table, th, td {
border: 5px solid White;
}
th {
font-weight: bold;
}
</style>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js">
</script>
<script>
// get the list of Open Projects for the Drop Down
$(function() {
google.script.run.withSuccessHandler(buildProjectList)
.getProjects();
});
function buildProjectList(options) {
var list = $('#projectList');
list.empty();
for (var i = 0; i < options.length; i++) {
list.append('<option value="' + options[i] + '">' + options[i] + '</option>');
}
}
// function called when a Project is selected from the Drop Down
function showResults() {
var selectedProject = $('#projectList').val();
google.script.run.withSuccessHandler(displayTeams)
.buildTeams(selectedProject);
google.script.run.withSuccessHandler(drawChart)
.buildChart(selectedProject); //THIS IS MY PROBLEM STATEMENT
}
// add the teams to the div
function displayTeams(html) {
console.log(“html: “ + html);
$('div.results_div').html(html);
}
// add the chart to the div (I HOPE)
google.charts.load('current', {'packages':['gantt']});
function drawChart(chartData) {
console.log("chart data: " + chartData); // chartData is missing here
var data = new google.visualization.DataTable();
data.addColumn('string', 'Task ID');
data.addColumn('string', 'Task Name');
data.addColumn('string', 'Resource');
data.addColumn('date', 'Start Date');
data.addColumn('date', 'End Date');
data.addColumn('number', 'Duration');
data.addColumn('number', 'Percent Complete');
data.addColumn('string', 'Dependencies');
data.addRows(chartData);
var options = {
height: 400,
gantt: {
trackHeight: 30
}
}
var chart = new google.visualization.Gantt(document.getElementByClassName("chart_div"));
chart.draw(data, options);
}
</script>
</head>
<body>
Select a Project from this list<br><br>
Projects:<br>
<select onchange='showResults();' id="projectList" name="project"></select>
<br>
<div class="results_div"></div>
<br>
<div class="chart_div"></div>
</body>
</html>
您可能正在发送不兼容的数据类型:根据客户端-服务器通信文档,Date
s的请求将失败。
我对google.script.run
通信的首选方法是:1)通过Date().getTime()
以毫秒形式发送所有Date
,因为这也可以避免时区问题和浏览器相关的日期字符串解析差异。然后,在客户端中,您可以通过调用new Date(milliseconds_value)
(即)将输入数据重新映射回Date
对象
function successHandler(rectangularArrayData) {
// Array indices of column values that need to be converted back to Date objects.
const dateIndices = [0, 3, 8 /**, etc... */];
// In general, pass your received data into a transformation function. This particular
// example assumes you only need to remap milliseconds to Date objects.
const chartData = rectangularArrayData.map(function (row) {
return row.map(function (col, index) {
// If this column index should be a date, make it a Date from the milliseconds input.
// Otherwise, do nothing to it.
return (dateIndices.indexOf(index) === -1) ? col : new Date(col);
});
});
...
}
和2)在发送之前将其序列化为JSON字符串。有时你只是发送了太复杂的对象,在return
之前通过(JSON.stringify
)将其转换为字符串有助于确保它不会在网络上被破坏。在客户端中,您的成功处理程序只需要通过JSON.parse()
重新实例化它。
你还可以做一些其他的事情(比如Array
s的for...in
迭代不明智且不可移植,使用new Array()
而不是[]
,或者执行多次比较来检查特定变量中几个文本值中的一个,而不是使用Array#indexOf
方法),这些都是可以改进的,但它们不在你的问题范围内,也不是问题的根源。