JSF 2 - Проверка компонента: проверка не удалась -> пустые значения заменяются последними действительными значениями из управляемого компонента - PullRequest
11 голосов
/ 14 октября 2010


Я не понимаю поведение JSF2 во время проверки. Надеюсь, кто-нибудь может мне помочь.

У меня есть форма, где поля проверяются после (ajax) отправки - хорошо
Если проверка не удалась, появляется сообщение об ошибке - хорошо

Для моего примера, когда я ввожу действительный день рождения и поле имя пусто, сообщение об ошибке для имя отображается после отправки.
Теперь, когда я ввожу действительное имя и удаляю ввод из поля birthday , отображается сообщение об ошибке для birthday (это нормально), но теперь старое 'valid' день рождения стоит также в поле ввода!?!

Как мне избежать этого поведения? Когда я отправляю пустое поле, я хочу увидеть сообщение об ошибке и пустое поле ...

Вот мой пример кода:

Я использую ManagedBean ( TestBean ), который содержит EntityBean ( Contact ). Контакт содержит проверки по аннотациям.

public class Contact implements Serializable {
    @NotNull 
    @Temporal(TemporalType.DATE)
    private Date birthday;

    @NotNull 
    @Size(min=3, max=15)
    private String name;

    //...
}

My ManagedBean :

@ManagedBean
@ViewScoped
public class TestBean implements Serializable {
    private Contact contact;

    @PostConstruct
    void init() {
        System.out.println("init...");
        contact = new Contact(); 
    }

    public void newContact(ActionEvent ae) {
        System.out.println("newContact...");
        contact = new Contact();
    }

    public void save() {
        System.out.println("save...");
        //TODO do something with contact...
    }

    public Contact getContact() { return contact; }

    public void setContact(Contact contact) {this.contact = contact;}
}

Вот моя страница JSF:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core" >      
 <h:body>
    <h:form>     
        <h:panelGrid columns="3">   

        <h:outputText value="Birthday: " />  
        <h:inputText id="birthday" value="#{testBean.contact.birthday}">
            <f:convertDateTime/>
        </h:inputText>  
        <h:message for="birthday" />  

        <h:outputText value="Name: " />  
        <h:inputText id="name" value="#{testBean.contact.name}"/>
        <h:message for="name" />

        </h:panelGrid>  

        <h:commandButton value="submit" action="#{testBean.save}"> 
            <f:ajax execute="@form" render="@form"/>
        </h:commandButton> 

        <h:commandButton value="newContact" actionListener="#{testBean.newContact}"
                         immediate="true"> 
            <f:ajax render="@form"/>
        </h:commandButton> 

    </h:form>
</h:body>
</html>

наконец фрагмент из web.xml

<context-param>
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
    <param-value>true</param-value>
</context-param>

<context-param>
    <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
    <param-value>true</param-value>
</context-param>

Спасибо за несколько советов

Ответы [ 4 ]

8 голосов
/ 06 декабря 2011

Ваша конкретная проблема вызвана

<context-param>
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
    <param-value>true</param-value>
</context-param>

и ошибкой (по крайней мере, недосмотром) в HtmlBasicRenderer#getCurrentValue() Мохарры:

if (component instanceof UIInput) {
    Object submittedValue = ((UIInput) component).getSubmittedValue();
    if (submittedValue != null) {
        // value may not be a String...
        return submittedValue.toString();
    }
}

String currentValue = null;
Object currentObj = getValue(component);
if (currentObj != null) {
    currentValue = getFormattedValue(context, component, currentObj);
}
return currentValue;

Обычно представленное значениеустановите null, когда компонент UIInput успешно преобразован и проверен.Когда JSF собирается снова отобразить значение, он сначала проверяет, не является ли переданное значение null, прежде чем возобновить отображение значения модели.Однако с этим параметром контекста он является null вместо пустой строки, когда он недопустим, и поэтому он всегда будет отображать исходное значение модели при удалении начального значения обязательного поля.

Для проверкиустановите значение параметра контекста на false или удалите его полностью.Вы увидите, что это работает как задумано.Однако это вернет тот недостаток, что значения вашей модели будут загромождены пустыми строками в пустых, но необязательных полях, и вы потеряете преимущество использования @NotNull аннотации проверки бина JSR 303.

Чтобы исправить это, вы должны изменить первую часть HtmlBasicRenderer#getCurrentValue() следующим образом:

if (component instanceof UIInput && !((UIInput) component).isValid()) {
    Object submittedValue = ((UIInput) component).getSubmittedValue();
    if (submittedValue != null) {
        // value may not be a String...
        return submittedValue.toString();
    } else {
        return null;
    }
}

Я уже сообщал об этом парням из Мохарры как выпуск 2262 .

0 голосов
/ 10 апреля 2012

Была похожая проблема, когда значение, загруженное из поддерживающего компонента, сбрасывалось, когда поле было отключено и другой компонент не прошел проверку.Мне пришлось сделать небольшое дополнение к коду BalusC, чтобы он заработал.

protected String getCurrentValue(FacesContext context,
                                     UIComponent component) {

        if (component instanceof UIInput && !((UIInput) component).isValid()) {
            Object submittedValue = ((UIInput) component).getSubmittedValue();
            if (submittedValue != null) {
                // value may not be a String...
                return submittedValue.toString();
            } else {
                return null;
            }
        }


        String currentValue = null;
        Object currentObj;

        if ( component instanceof UIInput && ((UIInput)component).isLocalValueSet() )
        {
           currentObj = ((UIInput)component).getLocalValue();
        }
        else {
            currentObj = getValue(component);
        }

        if (currentObj != null) {
            currentValue = getFormattedValue(context, component, currentObj);
        }
        return currentValue;


    }
0 голосов
/ 27 октября 2010

Аарон уже описывает поведение.

Проблема, которую я описал, существует и при нажатии кнопки «newContact».Если первая отправка недействительна (день рождения был введен, поле имени пусто) отображается сообщение об ошибке.ok.

После этого кнопка 'newContact' не обновляет (очищает) вид.Хотя модель была сброшена (contact = new Contact ()).

Я нашел несколько подсказок здесь: http://wiki.apache.org/myfaces/ClearInputComponents

Вот мое решение:

public void newContact(ActionEvent ae) {
    contact = new Contact();
    contact.setBirthday(new Date()); //for testing only

    resetForm(ae.getComponent());
}

private void resetForm(UIComponent uiComponent) {
    //get form component
    UIComponent parentComponent = uiComponent.getParent();
    if (uiComponent instanceof UIForm)
        resetFields(uiComponent);
    else if (parentComponent != null)
        resetForm(parentComponent);
    else
        resetFields(uiComponent);

}

private void resetFields(UIComponent baseComponent) {
    for (UIComponent c : baseComponent.getChildren()) {
        if (c.getChildCount() > 0)
            resetFields(c);

        if (c instanceof UIInput)
            ((UIInput) c).resetValue();
    }
}
0 голосов
/ 17 октября 2010

Я думаю, что при обычном использовании люди не будут вводить действительную дату, отправлять, а затем удалять дату перед повторной отправкой.Я понимаю, что вы обнаружили это во время тестирования, но, вероятно, люди просто пытаются успешно заполнить форму и не удаляют уже введенные данные, и в этом случае наилучшим функционалом может быть сохранение последнего действительного значения.

ЕслиВы настаиваете ... Кажется, что метод установки "birthday" никогда не вызывается, потому что значение недопустимо, и затем, когда страница повторно отображается, отображается текущее значение "birthday" (текущее значение является действительным значением, которое было ранеесохранены).Возможно, вы могли бы написать собственный валидатор, который устанавливает значение, а затем проверяет значение, но это не имеет большого смысла.Вам все равно придется сначала проверить значение в тех случаях, когда пользователи вводят текстовую строку, например, «вчера» вместо действительной даты, а затем вам нужно будет установить дату на что-то, основанное на этом недопустимом значении, а затем вам придетсядобавить сообщение в FacesContext.Таким образом, код должен сделать что-то вроде следующего.1) подтвердить значение даты2) если оно недопустимо, установите для поля значение, которое имеет смысл, и добавьте сообщение об ошибке в FacesContext.3) если он действителен, то используйте его.

Это выполнимо, но странно, потому что вы меняете значение поля, даже если переданное значение недопустимо ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...