Wicket TextField <BigDecimal>, который по умолчанию показывает 4 десятичных знака, но позволяет (легко) редактировать точное значение - PullRequest
2 голосов
/ 12 января 2012

Нам необходимо поддерживать высокую точность для определенных чисел (процентных ставок) в приложении, но мы все равно хотели бы показать их округленными до 4 десятичных знаков по умолчанию.

Таким образом, в таблице некоторые ячейки содержат значения в TextField<BigDecimal>, где пользователь может ввести значение с любой точностью, но в котором отображается значение с 4 десятичными знаками.Это делается с помощью пользовательского конвертера BigDecimal (, как описано в этом ответе ).

У нас также есть простая подсказка (атрибут title), показывающая точное значение (когда я говорю "точный ", есть, конечно, некоторый верхний предел шкалы, в настоящее время 16):

enter image description here

Эти поля имеют" onblur "AjaxFormComponentUpdatingBehavior, что приводит к немедленному сохранению измененного значения иОстальная часть таблицы обновлена.

Теперь есть две проблемы:

  1. Если пользователь щелкает поле, а затем щелкает где-то еще, округленное (4 десятичное) значение обновляется в доменеобъект & сохранялся без пользователя, даже понимая, что она что-то изменила.Т.е. точное значение теряется.
  2. Несколько хитрее: я бы хотел упростить редактирование точного значения.Т.е., когда текстовое поле щелкается (фокусируется), оно должно измениться, чтобы показать точное значение, чтобы пользователь мог легко редактировать это (а не округленное значение).

КакКак исправить # 1 Я изменил установщик базового DTO, чтобы он фактически не менял значение, если входящее новое значение такое же, но с меньшим масштабом.Но я ищу что-то, что решает # 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 под рукой, как в приведенном выше коде(выполняется при каждом обновлении таблицы), что я могу сделать, чтобы заменить видимое (редактируемое) значение в пользовательском интерфейсе ?

Могу ли я каким-то образом поменять местами преобразователь, когда полевнимание ?Установщика для конвертера не существует, но, возможно, создайте пользовательский подкласс TextField, который позволит вам изменить конвертер на лету ...?

В качестве крайней меры мы могли бы изменить конвертер (увеличить setMaximumFractionDigits), чтобыточные значения всегда будут отображаться (но это не решение этой конкретной проблемы, это просто обход ее стороной).

Ответы [ 2 ]

0 голосов
/ 14 января 2012

Я знаю, что уже слишком поздно, но почему бы не использовать два компонента?

Компонент 1 отображает округленное значение и всплывающую подсказку с точным значением. Когда вы щелкаете по нему, он скрывается и показывает другой компонент, который является стандартным текстовым полем с поведением onblur, которое скрывает компонент 2 и снова показывает компонент 1.

0 голосов
/ 13 января 2012

Ну, в конце концов я все заработал. Не используя чистый Wicket, но с небольшим взломом JavaScript.

Как уже упоминалось в вопросе, у меня уже было точное значение в атрибуте title поля. Поэтому я могу просто скопировать значение атрибута в качестве значения поля ввода.

Java

Для этих типов TextFields добавьте Поведение, которое вызывает функцию JS. Основным методом здесь является getMarkupId(), который возвращает (произвольный, динамический) <input> идентификатор элемента, который я могу использовать в JS.

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 (в файле .js, который загружается на соответствующей странице Wicket):

/**
 * 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 используется выше; вы, конечно, можете сделать это и без него.)

Единственная проблема с этим, по крайней мере, в нашем случае, это небольшая задержка (может быть, 200-500 мс) до вызова метода onUpdate(), что делает редактирование поля менее плавным , (Если пользователь быстро меняет значение, это изменение переопределяется кодом JS.)

Чтобы минимизировать это раздражение, я добавляю Поведение только тогда, когда оно действительно необходимо:

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

Не стесняйтесь размещать лучшие решения!

...