Vaadin 23:如何在ShortcutEventListener(Ctrl+S)中同步字段值?
Vaadin 23表单Ctrl+S快捷键同步字段值问题
需求
在现有Vaadin 23表单中添加Ctrl+S快捷键以触发保存操作。
代码示例
@Route("sandbox") public class SandboxView extends VerticalLayout { public SandboxView() { TextField textField = new TextField(); Shortcuts.addShortcutListener(this, new ShortcutEventListener() { @Override public void onShortcut(ShortcutEvent event) { System.out.println("Saving value ... "+textField.getValue()); } }, Key.KEY_S, KeyModifier.CONTROL).listenOn(this); this.add(textField); } }
问题
用户在TextField中输入文本后直接按Ctrl+S(未失焦),ShortcutEventListener内的textField.getValue()返回聚焦前的旧值。
临时方案
- 方案A:用户先移出TextField焦点再按Ctrl+S,有效但易出错。
- 方案B:设置
valueChangeMode为EAGER,即textField.setValueChangeMode(ValueChangeMode.EAGER);,但会增加流量和服务器负载,不适用。
核心疑问
能否在ShortcutEventListener中同步表单所有字段到后端?
已尝试操作
- 上述临时方案
- 调用
textfield.blur()触发JS的blur方法,但同步在ShortcutEventListener执行后完成 - 使用Binder并调用
binder.writeBeanIfValid(binder.getBean());,Bean仍保留旧值
解决方案
方法1:强制同步当前聚焦字段值后执行保存
通过JS强制触发当前聚焦元素的失焦操作,让客户端立即将最新值同步到服务器,待同步完成后再执行保存逻辑:
@Route("sandbox") public class SandboxView extends VerticalLayout { public SandboxView() { TextField textField = new TextField(); Shortcuts.addShortcutListener(this, event -> { // 触发当前聚焦元素失焦+重新聚焦,同步最新值到服务器 UI.getCurrent().getPage().executeJs("document.activeElement.blur(); document.activeElement.focus();") .then(result -> { // 同步完成后执行保存 System.out.println("Saving value ... "+textField.getValue()); }); }, Key.KEY_S, KeyModifier.CONTROL).listenOn(this); this.add(textField); } }
方法2:配合Binder同步字段到Bean
如果使用Binder绑定表单与数据Bean,同样先触发字段值同步,再将字段最新值写入Bean后执行后端保存:
@Route("sandbox") public class SandboxView extends VerticalLayout { private final UserBean bean = new UserBean(); private final Binder<UserBean> binder = new Binder<>(UserBean.class); public SandboxView() { TextField textField = new TextField(); binder.forField(textField).bind(UserBean::getName, UserBean::setName); binder.readBean(bean); Shortcuts.addShortcutListener(this, event -> { UI.getCurrent().getPage().executeJs("document.activeElement.blur();") .then(result -> { try { // 将字段最新值写入Bean binder.writeBean(bean); System.out.println("Saving bean value ... "+bean.getName()); // 此处执行后端保存逻辑 } catch (ValidationException e) { // 处理验证错误 } }); }, Key.KEY_S, KeyModifier.CONTROL).listenOn(this); this.add(textField); } public static class UserBean { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } }
原理说明
Vaadin字段默认仅在失焦时同步客户端最新值到服务器,快捷键触发时字段仍聚焦,服务器端只能拿到旧值。通过JS强制失焦的方式,既避免了EAGER模式的频繁请求,也无需用户手动操作失焦,就能确保保存时拿到最新的字段值。
内容的提问来源于stack exchange,提问作者sdo
相关产品推荐
相关产品推荐

