如何优雅实现FormIO表格元素的列数据求和?
计算FormIO表格指定列数值总和的优化方案
我需要计算FormIO表格中某列的数值总和,当前使用的脚本虽能实现功能,但代码冗余度很高:
if(data['personesAtesesNoBinari17'] >= 0 || data['personesAtesesNoBinari1631'] >= 0 || data['personesAtesesNoBinari3066'] >= 0 || data['personesAtesesNoBinari67'] >= 0){ if(data['personesAtesesNoBinari17'] === undefined){ data['personesAtesesNoBinari17'] = 0; } if(data['personesAtesesNoBinari1631'] === undefined){ data['personesAtesesNoBinari1631'] = 0; } if(data['personesAtesesNoBinari3066'] === undefined){ data['personesAtesesNoBinari3066'] = 0; } if(data['personesAtesesNoBinari67'] === undefined){ data['personesAtesesNoBinari67'] = 0; } data['personesAtesesNoBinariTotal2'] = data['personesAtesesNoBinari17'] + data['personesAtesesNoBinari1631'] + data['personesAtesesNoBinari3066'] + data['personesAtesesNoBinari67']; }else{ data['personesAtesesNoBinariTotal2'] = 0; }
除输出项
data['personesAtesesVoluntariatTotal1']外,每个data['']都是含数字的单元格。
我曾尝试以下更简洁的循环脚本,该脚本在Visual Studio Code中可正常运行,但在FormIO环境下无法生效:
let result = 0; for (let i = 1; i < (data['tableName'].rows.length-1); i++) { result += parseInt(data['tableName'].rows[i].cells[1]); } data['outputName'] = result;
以下是该表格的JSON配置:
{ "label": "Table", "cellAlignment": "left", "customClass": "standardTable tableSpacing", "bordered": true, "hover": true, "key": "table22", "type": "table", "numRows": 6, "numCols": 4, "input": false, "tableView": false, "rows": [ [ { "components": [] }, { "components": [ { "label": "HTML", "attrs": [ { "attr": "", "value": "" } ], "content": "<div style=\"text-align:center ; background-color : #900000 ; height: 100%;\"><h3 style=\"color:white;font-weight: bold;\">No binari</h3></div>", "refreshOnChange": false, "key": "html154", "type": "htmlelement", "input": false, "tableView": false } ] } ], [ { "components": [ { "label": "HTML", "attrs": [ { "attr": "", "value": "" } ], "content": "<div>Persones de menys de 16 anys</div>", "refreshOnChange": false, "key": "html155", "type": "htmlelement", "input": false, "tableView": false } ] }, { "components": [ { "label": "Number", "hideLabel": true, "mask": false, "tableView": false, "delimiter": false, "requireDecimal": false, "inputFormat": "plain", "truncateMultipleSpaces": false, "key": "personesAtesesNoBinari17", "type": "number", "input": true } ] } ], [ { "components": [ { "label": "HTML", "attrs": [ { "attr": "", "value": "" } ], "content": "<div>Persones entre 16 a 29 anys</div>", "refreshOnChange": false, "key": "html156", "type": "htmlelement", "input": false, "tableView": false } ] }, { "components": [ { "label": "Number", "hideLabel": true, "mask": false, "tableView": false, "delimiter": false, "requireDecimal": false, "inputFormat": "plain", "truncateMultipleSpaces": false, "key": "personesAtesesNoBinari1631", "type": "number", "input": true } ] } ], [ { "components": [ { "label": "HTML", "attrs": [ { "attr": "", "value": "" } ], "content": "<div>Persones entre 30 i 64 anys</div>", "refreshOnChange": false, "key": "html157", "type": "htmlelement", "input": false, "tableView": false } ] }, { "components": [ { "label": "Number", "hideLabel": true, "mask": false, "tableView": false, "delimiter": false, "requireDecimal": false, "inputFormat": "plain", "truncateMultipleSpaces": false, "key": "personesAtesesNoBinari3066", "type": "number", "input": true } ] } ], [ { "components": [ { "label": "HTML", "attrs": [ { "attr": "", "value": "" } ], "content": "<div>Persones de 65 anys o més</div>", "refreshOnChange": false, "key": "html158", "type": "htmlelement", "input": false, "tableView": false } ] }, { "components": [ { "label": "Number", "hideLabel": true, "mask": false, "tableView": false, "delimiter": false, "requireDecimal": false, "inputFormat": "plain", "truncateMultipleSpaces": false, "key": "personesAtesesNoBinari67", "type": "number", "input": true } ] } ], [ { "components": [ { "label": "HTML", "attrs": [ { "attr": "", "value": "" } ], "content": "<div>Total</div>", "refreshOnChange": false, "key": "html159", "type": "htmlelement", "input": false, "tableView": false } ] }, { "components": [ { "label": "Number", "hideLabel": true, "mask": false, "disabled": true, "tableView": false, "defaultValue": 0, "delimiter": false, "requireDecimal": false, "inputFormat": "plain", "truncateMultipleSpaces": false, "key": "personesAtesesNoBinariTotal2", "logic": [ { "name": "SumatoriPersonesAtesesNoBinariTotal", "trigger": { "type": "javascript", "javascript": "if(data['personesAtesesNoBinari17'] >= 0 || data['personesAtesesNoBinari1631'] >= 0 || data['personesAtesesNoBinari3066'] >= 0 || data['personesAtesesNoBinari67'] >= 0){ if(data['personesAtesesNoBinari17'] === undefined){ data['personesAtesesNoBinari17'] = 0; } if(data['personesAtesesNoBinari1631'] === undefined){ data['personesAtesesNoBinari1631'] = 0; } if(data['personesAtesesNoBinari3066'] === undefined){ data['personesAtesesNoBinari3066'] = 0; } if(data['personesAtesesNoBinari67'] === undefined){ data['personesAtesesNoBinari67'] = 0; } data['personesAtesesNoBinariTotal2'] = data['personesAtesesNoBinari17'] + data['personesAtesesNoBinari1631'] + data['personesAtesesNoBinari3066'] + data['personesAtesesNoBinari67']; }else{ data['personesAtesesNoBinariTotal2'] = 0; }" }, "actions": [ { "name": "SumatoriPersonesAtesesNoBinariTotal", "type": "value", "value": "value = data['personesAtesesNoBinariTotal2'];" } ] } ], "type": "number", "personesAtesesNoBinariTotal2": 0, "personesAtesesNoBinariTotal": 0, "input": true } ] } ] ] }
优化方案
方案一:简化现有字段求和逻辑
将需要求和的字段放入数组,使用reduce方法遍历计算总和,自动处理undefined或非数值的情况,代码简洁且功能完整:
// 定义要求和的字段列表 const targetFields = [ 'personesAtesesNoBinari17', 'personesAtesesNoBinari1631', 'personesAtesesNoBinari3066', 'personesAtesesNoBinari67' ]; // 计算总和,自动将无效值转为0 data['personesAtesesNoBinariTotal2'] = targetFields.reduce((sum, fieldKey) => { const val = data[fieldKey]; return sum + (typeof val === 'number' && !isNaN(val) ? val : 0); }, 0);
方案二:解决循环脚本失效问题
原循环脚本失效的核心原因:FormIO中表格内的用户输入值不会存储在表格组件的rows属性里,而是直接以每个单元格组件的key作为属性挂载在data对象下。所以无法通过data['tableName'].rows[i].cells[1]获取值。
如果想要动态遍历目标列的字段(比如字段可能后续新增),可以先提取表格配置中目标列的所有数字组件key,再求和:
// 获取表格组件的配置(假设在FormIO逻辑中可通过组件实例获取,或提前定义列的组件key) const tableConfig = data._schema.components.find(comp => comp.key === 'table22'); // 提取第二列(索引1)的所有数字组件key const columnFields = tableConfig.rows .slice(1, -1) // 跳过表头和总计行 .map(row => row[1].components[0].key); // 计算总和 data['personesAtesesNoBinariTotal2'] = columnFields.reduce((sum, fieldKey) => { const val = data[fieldKey]; return sum + (typeof val === 'number' && !isNaN(val) ? val : 0); }, 0);
注意:如果在FormIO的逻辑脚本中无法直接获取_schema,建议直接使用方案一的字段数组方式,更稳定可靠。
内容的提问来源于stack exchange,提问作者Javi
相关产品推荐
相关产品推荐

