如何在Vaadin 8 Grid组件编辑模式下动态计算列值
Vaadin 8 Grid 实时计算列C(A+B)实现方案
无需JavaScript的实现方案
Vaadin 8 Grid可以通过绑定数据模型的属性变更实现实时计算,完全不需要依赖JavaScript,这也是最符合Vaadin组件设计思想的方案:
1. 定义带自动计算逻辑的数据实体
给A、B字段的setter方法添加计算逻辑,当A或B的值修改时,自动更新C的值:
public class DataItem { private Double a; private Double b; private Double c; public Double getA() { return a; } public void setA(Double a) { this.a = a; calculateC(); } public Double getB() { return b; } public void setB(Double b) { this.b = b; calculateC(); } // C为只读计算值,不需要setter public Double getC() { return c; } private void calculateC() { this.c = (a != null ? a : 0) + (b != null ? b : 0); } }
2. 配置Grid编辑器
将Grid的编辑器组件与实体属性绑定,当用户修改A/B的值时,Binder会自动调用实体的setter方法,触发C的计算并实时刷新显示:
Grid<DataItem> grid = new Grid<>(DataItem.class); grid.setColumns("a", "b", "c"); // 启用编辑器 grid.getEditor().setEnabled(true); Binder<DataItem> binder = grid.getEditor().getBinder(); // 配置A列编辑器 TextField aField = new TextField(); binder.forField(aField) .withConverter(StringToDoubleConverter.forNumberField("请输入有效数字")) .bind(DataItem::getA, DataItem::setA); grid.getColumn("a").setEditorComponent(aField); // 配置B列编辑器 TextField bField = new TextField(); binder.forField(bField) .withConverter(StringToDoubleConverter.forNumberField("请输入有效数字")) .bind(DataItem::getB, DataItem::setB); grid.getColumn("b").setEditorComponent(bField); // 标记C列为不可编辑 grid.getColumn("c").setEditable(false);
用户在编辑模式下修改A/B的值后,C列会自动显示计算结果,无需点击保存按钮。
必须使用JavaScript的场景解决方法
如果因业务限制无法修改数据实体,可通过Vaadin的客户端API绑定事件,解决Grid DOM元素无ID的问题:
核心思路
利用Vaadin组件的ElementAPI给编辑器组件绑定blur事件,通过DOM层级关系定位当前行的元素,完成计算后更新C列内容:
Grid<DataItem> grid = new Grid<>(DataItem.class); grid.setColumns("a", "b", "c"); grid.getEditor().setEnabled(true); Binder<DataItem> binder = grid.getEditor().getBinder(); // 配置A列编辑器并绑定blur事件 TextField aField = new TextField(); binder.bind(aField, DataItem::getA, DataItem::setA); grid.getColumn("a").setEditorComponent(aField); aField.getElement().addEventListener("blur", event -> { // 编写JS片段,通过DOM层级定位元素 String jsCode = "var currentRow = $0.closest('.v-grid-row'); " + "var aValue = parseFloat($0.value) || 0; " + "var bInput = currentRow.querySelector('.v-text-field:nth-child(2) input'); " + "var bValue = parseFloat(bInput.value) || 0; " + "var cCell = currentRow.querySelector('.v-grid-cell:nth-child(3)'); " + "cCell.textContent = (aValue + bValue).toFixed(2);"; aField.getElement().executeJavaScript(jsCode); }); // 配置B列编辑器并绑定blur事件 TextField bField = new TextField(); binder.bind(bField, DataItem::getB, DataItem::setB); grid.getColumn("b").setEditorComponent(bField); bField.getElement().addEventListener("blur", event -> { String jsCode = "var currentRow = $0.closest('.v-grid-row'); " + "var bValue = parseFloat($0.value) || 0; " + "var aInput = currentRow.querySelector('.v-text-field:nth-child(1) input'); " + "var aValue = parseFloat(aInput.value) || 0; " + "var cCell = currentRow.querySelector('.v-grid-cell:nth-child(3)'); " + "cCell.textContent = (aValue + bValue).toFixed(2);"; bField.getElement().executeJavaScript(jsCode); }); // 标记C列为不可编辑 grid.getColumn("c").setEditable(false);
代码说明
$0是Vaadin内置的变量,指代当前触发事件的DOM元素- 通过
closest('.v-grid-row')定位当前编辑行 - 用
querySelector根据列的顺序(nth-child索引)找到同行情报的输入框和C列单元格 - 计算后直接修改C列单元格的文本内容
内容的提问来源于stack exchange,提问作者Hessam
相关产品推荐
相关产品推荐

