GAS Web应用图表渲染报错及HTML样式引用问题求助
Google Apps Script Web应用:解决下拉筛选图表的"Cannot read properties of undefined (reading 'length')"报错
问题场景
基于Google Apps Script开发Web应用,目标实现带下拉筛选的图表功能:下拉选项包含All、North、South,页面加载默认渲染All对应数据,选择选项点击按钮后筛选图表。目前遇到两个核心问题:
- 报错
Cannot read properties of undefined (reading 'length'),导致开发停滞; - 移除
<?!= include('page_style'); ?>标签后图表可正常渲染,但CSS样式失效;重新添加该标签则样式正常,但报错重现。
报错原因分析
- 模板变量与DOM元素ID冲突:HTML中
<select>元素的ID设为dg,和模板中传入的下拉选项数组变量dg重名。模板渲染循环<? for(var i=0; i< dg.length;i++){ ?>时,dg被解析为DOM元素而非模板变量,因此读取length属性时触发undefined报错。 - 缺失关键函数:
get_dg函数中调用了return_array.filter(uniquelists),但未提供uniquelists去重函数的实现,导致返回数组异常,间接引发模板变量赋值错误。 - doPost方法变量覆盖:doPost函数中先声明
var dg = e.parameters.dg.toString();,之后又重新声明var dg = get_dg();,虽不直接引发当前报错,但属于不良编码习惯,可能导致后续逻辑问题。
修复方案
1. 解决变量名冲突
修改HTML中<select>的ID,避免与模板变量dg重名,例如改为select_dg。
2. 补充缺失的去重函数
在GAS脚本中添加uniquelists函数,确保get_dg返回正确的唯一值数组。
3. 修复doPost变量覆盖问题
将doPost中接收请求参数的变量名改为selectedDg,避免覆盖后续获取的下拉选项数组。
4. 完善图表筛选逻辑
修改draw_linechart函数,使其接收筛选参数,返回对应的数据;同时在HTML中绑定按钮点击事件,触发图表重新渲染。
完整修正代码
GAS脚本
function doGet(e){ var html = HtmlService.createTemplateFromFile('pages'); var dg = get_dg(); html.dg = dg; return html.evaluate(); } function doPost(e){ var selectedDg = e.parameters.s_d; // 对应HTML中select的name属性s_d var html = HtmlService.createTemplateFromFile('pages'); var dg = get_dg(); html.dg = dg; html.selectedDg = selectedDg; // 将选中的筛选值传入模板 return html.evaluate(); } function getUrl() { return ScriptApp.getService().getUrl(); } function include(filename) { return HtmlService.createHtmlOutputFromFile(filename) .getContent(); } // 补充去重函数,实现数组去重 function uniquelists(value, index, self) { return self.indexOf(value) === index; } function get_dg(){ var d_useremail = Session.getActiveUser().getEmail(); var ss = SpreadsheetApp.openById('XXXXXXXXX'); var metrics_sheet = ss.getSheetByName('sheet'); var getlastrow = metrics_sheet.getLastRow(); var return_array = []; for(var i = 2; i <= getlastrow; i++) { if(metrics_sheet.getRange(i, 1).getValue() === d_useremail) { return_array.push(metrics_sheet.getRange(i, 2).getValue()); } } Logger.log(return_array); return return_array.filter(uniquelists); } // 修改为接收筛选参数的图表数据获取函数 function draw_linechart(filterValue = 'All'){ var ss = SpreadsheetApp.openById('XXXXXXXXXXXXXXX'); var metrics_sheet = ss.getSheetByName('test_chart'); var c_data = metrics_sheet.getRange("A1:B").getValues(); // 根据筛选值过滤数据(假设第一列为区域标识,第二列为数值,可根据实际结构调整) if(filterValue !== 'All'){ c_data = c_data.filter(row => row[0] === filterValue); // 若无匹配数据,保留表头避免图表报错 if(c_data.length === 0){ c_data = [c_data[0]]; } } var c_data1 = JSON.stringify(c_data); return c_data1; }
page_style CSS
.c_line_chart{ display:flex; width:90%; height:90px; margin-left:35px; }
pages HTML
<!DOCTYPE html> <html> <head> <base target="_top"> <?!= include('page_style'); ?> <script src="https://www.gstatic.com/charts/loader.js"></script> <script type="text/javascript"> google.charts.load('current',{'packages':['corechart']}); // 获取页面加载时的筛选值,默认All var initialFilter = "<?= selectedDg || 'All' ?>"; google.charts.setOnLoadCallback(() => drawchart(initialFilter)); function drawchart(filterValue){ google.script.run.withSuccessHandler(displaychart).draw_linechart(filterValue); } function displaychart(c_data1){ var chartdata = new google.visualization.arrayToDataTable(JSON.parse(c_data1)); console.log(chartdata); var options={ title: 'Checking the Charts', is3D: true } var chart = new google.visualization.LineChart(document.getElementById('line_chart')); chart.draw(chartdata,options); } // 绑定按钮点击事件,触发图表筛选渲染 document.addEventListener('DOMContentLoaded', function() { document.getElementById('btn').addEventListener('click', function() { var selectedValue = document.getElementById('select_dg').value; drawchart(selectedValue); }); }); </script> </head> <body> <?var url = getUrl(); ?> <form method="post" action="<?= url ?>" > <div class="filter_container"> <br><br> <div class="box1"> <label class="label_"> DGraph </label> <br> <!-- 修改select的ID为select_dg,避免和模板变量dg冲突 --> <select name="s_d" id="select_dg" class="cselect"> <option value="All" <?= selectedDg === 'All' || !selectedDg ? 'selected' : '' ?>>All</option> <? for(var i=0; i< dg.length;i++){ ?> <option value="<?= dg[i] ?>" <?= selectedDg === dg[i] ? 'selected' : '' ?>><?= dg[i] ?></option> <? } ?> </select><br><br> </div> <button id ="btn" type="button">Click!</button> </div> <div id ="line_chart" class="c_line_chart"></div> </form> </body> </html>
内容的提问来源于stack exchange,提问作者Tpk43
相关产品推荐
相关产品推荐

