Wicket TextField <bigdecimal>默认显示4位小数,但允许(轻松)编辑确切的值</b​​igdecimal>

时间:2012-01-12 13:45:17

标签: java wicket

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

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

我们还有一个简单的工具提示(标题属性),显示确切的值(当我说“确切”时,当然有一些规模的上限,目前为16):

enter image description here

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

现在,有两个问题:

  1. 如果用户点击该字段,则点击其他地方,四舍五入(4 十进制)值在域对象&amp;中更新坚持没有 用户甚至意识到她改变了什么。即,确切的价值会丢失。
  2. 有点棘手:我想简单地编辑确切的值。 即,当单击(聚焦)文本字段时,它应该更改为 显示确切的值,以便用户可以轻松编辑(而不是 舍入值)。
  3. 作为#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);
          }
     }
    

    拥有字段,域对象&amp;上面代码中的确切BigDecimal值(在表的每次更新时执行),我可以做什么来替换UI中可见(可编辑)的值

    当字段聚焦时,我可以以某种方式交换转换器吗?转换器没有setter,但是可能会创建一个自定义的TextField子类,允许你动态更改转换器......?

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

2 个答案:

答案 0 :(得分:0)

好吧,我最终得到了它。不是使用纯粹的Wicket,而是使用一个小的JavaScript hack。

正如问题所述,我已经在该字段的title属性中得到了确切的值。所以我可以将属性值复制为输入字段的值。

<强>爪哇

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

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

答案 1 :(得分:0)

我知道现在为时已晚,但为何不使用两个组件?

组件1显示舍入值,工具提示显示精确值。当您单击它时,它会隐藏自身并显示另一个组件,这是一个标准文本字段,其行为onblur会隐藏组件2并再次显示组件1.