JSF 2.0: как пропустить проверку bean-компонента JSR-303?
Как пропустить проверку JSR-303 Bean с помощью JSF при нажатии кнопки?
Немного длинный вопрос, чтобы объяснить несколько подходов... Рассмотрим список в форме:
<h:form id="form">
<h:commandButton value="Add row">
<f:ajax execute="foo" listener="#{bean.add()}" render="foo" />
</h:commandButton>
<h:dataTable id="foo" var="foo" value="#{bean.foos}">
<h:column>
Name: <h:inputText id="field" value="#{foo.name}" required="true" />
<h:messages for="field" />
</h:column>
<h:column>
<h:commandButton value="Remove">
<f:ajax execute=":form:foo" listener="#{bean.remove(foo)}" render=":form:foo" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
Когда пользователь нажимает добавить или удалить строку, действие должно выполняться без проверки. Проблема в том, что JSF повторно отображает весь список и пытается его проверить. Если есть черновые изменения, которые не проверяются, возникают ошибки проверки, и метод слушателя никогда не вызывается (поскольку неудачная проверка предотвращает это). Тем не менее, добавив immediate="true"
в f:ajax позволяет выполнять метод, несмотря на ошибки проверки. Тем не менее, ошибки проверки все еще происходят и отображаются здесь.
Я вижу два варианта:
1) Используйте немедленный = "истина" и не показывать ошибки проверки
Для неподтвержденных кнопок, установите немедленное ="true", а для h: messages do:
<h:messages rendered="#{param['SHOW_VALIDATION']}" />
Затем установите кнопку Save (которая должна попытаться сохранить форму), чтобы отправить этот параметр:
<h:commandButton>
<f:param name="SHOW_VALIDATION" value="true" />
</h:commandButton>
Это вызывает проверку, но сообщения просто не отображаются, кроме случаев, когда SHOW_VALIDATION
параметр присутствует.
2) Объявить валидацию в Facelets условно:
<h:inputText>
<f:validateRequired disabled="#{!param['VALIDATE']}" />
</h:inputText>
И кнопка Сохранить:
<h:commandButton>
<f:param name="VALIDATE" value="true" />
</h:commandButton>
Это заставляет поля проверять только когда VALIDATE
параметр присутствует (= когда нажата кнопка Save).
Но это похоже на хаки. Как я могу просто использовать JSR-303 Bean Validation, но пропустить его при объявлении?
4 ответа
Установите ваши обработчики событий как immediate=true
и позвонить FacesContext.renderResponse()
прежде чем выйти из них.
ОБНОВЛЕНИЕ:
Изменения в вашем примере формы:
<h:form id="form">
<h:commandButton value="Add row">
<!-- Added immediate="true" to call bean.add() before validation phase -->
<f:ajax execute="foo" listener="#{bean.add()}" render="foo" immediate="true"/>
</h:commandButton>
<h:dataTable id="foo" var="foo" value="#{bean.foos}">
<h:column>
Name: <h:inputText id="field" value="#{foo.name}" required="true" />
<h:messages for="field" />
</h:column>
<h:column>
<h:commandButton value="Remove">
<!-- Added immediate="true" to call bean.remove() before validation phase -->
<f:ajax execute=":form:foo" listener="#{bean.remove(foo)}" render=":form:foo" immediate="true"/>
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
Изменения в вашем коде бина:
...
public void add() {
// Your add() code
...
// Added FacesContext.renderResponse() call to skip to render response phase
FacesContext.getCurrentInstance().renderResponse();
}
...
public void remove() {
// Your remove() code
...
// Added FacesContext.renderResponse() call to skip to render response phase
FacesContext.getCurrentInstance().renderResponse();
}
...
Вы можете отключить проверку bean-компонента с помощью тега f:validateBean, у которого отключен атрибут.
Пример:
<h:inputText value="#{bean.name}">
<f:validateBean disabled="#{anotherBean.flag}"/>
</h:inputText>
Мы только что опубликовали решение этой проблемы. Полная информация здесь: http://www.springfuse.com/2011/12/15/skip-jsf-validation-depending-on-action.html
Короче говоря, он использует атрибут привязки тега validateBean. Это позволит вам перехватить метод validate и принять решение, основываясь на нажатой кнопке, пропустить его или нет.
Ситуация: в коде страницы есть большая форма с большим количеством полей ввода. Есть несколько кнопок, каждая из которых указывает на отдельное действие в отдельном компоненте.
Решение, которое сработало для меня...
- В коде страницы: добавить
immediate="true"
и предоставьте идентификатор для полей ввода, которые вы хотите использовать в компоненте.
<p:inputText id="someHtmlInputId" maxlength="30" value="#{beanName.attr}" /> <p:commandButton id="someHtmlButtonId" actionListener="#{beanName.doStuff}" value="Button Label" ajax="false" immediate="true"/>
- В зернах
doStuff
Метод получает параметры по фрагменту имени, прежде чем входное имя JSF поместит некоторые другие идентификаторы, и полученное имя параметра может выглядеть следующим образом: someFormId:j_idt54:someHtmlInputId
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap(); if (params != null) { for (String k: params.keySet()) if (k.indexOf("someHtmlInputId") != -1) params.get(k); // This is Your input parameter value waiting to be processed ;) }