java - Wicket TextField<BigDecimal> 默认显示 4 位小数,但允许(轻松)编辑精确值

标签 java wicket

我们需要在应用程序中支持某些数字(利率)的高精度,但我们仍然希望在默认情况下将它们显示为四舍五入到小数点后 4 位。

因此,在表格中,一些单元格包含 TextField<BigDecimal> 中的比率用户可以在其中输入任意精度的值,但显示的值带有 4 个小数点。这是通过自定义 BigDecimal 转换器 ( as documented in this answer ) 完成的。

我们还有一个简单的工具提示(title 属性),显示精确值(当我说“精确”时,当然有一些比例上限,目前为 16):

enter image description here

这些字段具有“onblur”AjaxFormComponentUpdatingBehavior,这会导致立即保存更改的值并更新表的其余部分。

现在,有两个问题:

  1. 如果用户点击该字段,然后点击其他地方,四舍五入(4 decimal) 值在域对象中更新并在没有 用户甚至意识到她改变了任何东西。即,确切的值丢失了。
  2. 有点棘手:我想让编辑准确的值变得容易。 即,单击(聚焦)文本字段时,它应更改为 显示确切的值,以便用户可以轻松编辑该值(而不是 四舍五入的值(value))。

作为对 #1 的 hacky 修复,我更改了底层 DTO 的 setter ,这样如果传入的新值相同但规模较小,它实际上不会更改值。但我正在寻找解决 #2 的方法(它也会自动处理 #1)。

final TextField<BigDecimal> field;
BigDecimal interestRate = ...; // current exact value from the model object

field.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
    @Override
    protected void onUpdate(AjaxRequestTarget target) {
        // something I could do here? using e.g. 
        // field.setModelObject(), field.setConvertedInput() 
        // or field.getConverter(BigDecimal.class);
      }
 }

有了上面代码中的字段、域对象和确切的 BigDecimal 值(在每次更新表时执行),我该怎么做才能替换 UI 中可见(可编辑)的值?

当场聚焦时,我能否以某种方式交换转换器?转换器没有 setter ,但也许可以创建一个自定义 TextField 子类,允许您即时更改转换器...?

作为最后的手段,我们可以更改转换器(增加 setMaximumFractionDigits)以便始终显示准确的值(但这不是解决这个特定问题的方法,它只是回避它)。

最佳答案

好吧,我最终成功了。不使用纯 Wicket,而是使用一个小的 JavaScript hack。

如问题中所述,我已经在 title 中获得了准确的值字段的属性。所以我可以只复制属性值作为输入字段的值。

Java:

对于这些类型的 TextFields,添加一个调用 JS 函数的 Behavior。这里的基本方法是 getMarkupId() 它返回(任意的,动态的)<input>我可以在 JS 中使用的元素 ID。

private void addPreservePrecisionBehavior(final TextField<BigDecimal> field) {
    field.add(new AjaxFormComponentUpdatingBehavior("onclick") {
        @Override
        protected void onUpdate(AjaxRequestTarget target) {
            String js = String.format("copyExactValueFromTitle('%s')", field.getMarkupId());
            target.appendJavascript(js);
        }
    });
}

JavaScript(在相关 Wicket 页面上加载的 .js 文件中):

/**
 * Takes the specified input field's title and sets it as the field's value.
 *
 * @param elementId ID of an input element
 */
function copyExactValueFromTitle(elementId) {
    if (!elementId) {
        return;
    }
    var input = $('#' + elementId);
    var exactValue = input.attr("title");
    if (exactValue) {
        input.val(exactValue);
    }
}

(请注意,上面使用了 jQuery;您当然也可以在没有它的情况下执行此操作。)

唯一的问题是,至少在我们的例子中,在 onUpdate() 之前有轻微的延迟(可能是 200-500 毫秒)方法被调用,这使得编辑字段变得不那么流畅。 (如果用户快速更改值,该更改将被 JS 代码覆盖。)

为了尽量减少这种烦恼,我只在真正需要时才添加行为:

 if (interestRate != null && interestRate.stripTrailingZeros().scale() > 4) {
     addPreservePrecisionBehavior(field);
 }

随时发布更好的解决方案!

关于java - Wicket TextField<BigDecimal> 默认显示 4 位小数,但允许(轻松)编辑精确值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8836085/

相关文章:

java - 是否可以在键入 JTextField 时将其计算到 JLabel 中?

java - Grails 新项目无法解析依赖项

wicket - 在Wicket DropDownChoice中,如何将 "Choose one"替换为另一个文本

java - $push 和 $set 在同一个 MongoDB 更新中

java - PowerMockito UnfinishedStubbingException

Java套接字问题

ajax - 为什么运行多个Wicket应用程序会导致AJAX冲突?

java - Controller 和 Wicket 页面的设计模式帮助

java - 使用 jpa 出现 NoViableAltException

java - 使用特定于字段的反馈标签时如何避免多余的 Wicket 日志警告?