You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:01:43