JSF 2.0: Как пропустить проверку JSR-303 bean?
Как пропустить проверку 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" и не показывайте ошибки проверки
Для неавтоматизирующих кнопок установите немедленное = "true" и для h: сообщения выполните:
<h:messages rendered="#{param['SHOW_VALIDATION']}" />
Затем установите Save-button (на самом деле попытайтесь сохранить форму), чтобы отправить этот параметр:
<h:commandButton>
<f:param name="SHOW_VALIDATION" value="true" />
</h:commandButton>
Это вызывает проверку, но сообщения просто не отображаются, кроме случаев, когда присутствует параметр SHOW_VALIDATION
.
2) Объявить валидацию в треугольниках условно:
<h:inputText>
<f:validateRequired disabled="#{!param['VALIDATE']}" />
</h:inputText>
И Сохранить кнопку:
<h:commandButton>
<f:param name="VALIDATE" value="true" />
</h:commandButton>
Это приводит к тому, что поля проверяются только при наличии параметра VALIDATE
(= при нажатии кнопки "Сохранить" ).
Но это похоже на хаки. Как я могу просто использовать JSR-303 Bean Validation, но пропустить его при объявлении?
Ответы
Ответ 1
Установите обработчики событий как 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>
Изменения в коде bean:
...
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();
}
...
Ответ 2
Вы можете отключить проверку bean с тегом f: validateBean, у которого есть атрибут отключен.
Пример:
<h:inputText value="#{bean.name}">
<f:validateBean disabled="#{anotherBean.flag}"/>
</h:inputText>
Ответ 3
Мы только что опубликовали решение этой проблемы.
Полная информация здесь:
http://www.springfuse.com/2011/12/15/skip-jsf-validation-depending-on-action.html
Короче говоря, он использует атрибут привязки тега validateBean.
Это позволит вам перехватить метод проверки и решить, на основе нажатой кнопки, разрешить ли это пройти или нет.
Ответ 4
Ситуация:
В коде страницы есть большая форма с большим количеством полей ввода. Существует несколько кнопок, каждая из которых указывает на отдельное действие в отдельном bean.
Решение, которое сработало для меня...
- В коде страницы: добавьте
immediate="true"
к кнопке и укажите идентификатор для полей ввода, которые вы хотите использовать в bean.
<p:inputText id="someHtmlInputId"
maxlength="30"
value="#{beanName.attr}" />
<p:commandButton id="someHtmlButtonId"
actionListener="#{beanName.doStuff}"
value="Button Label"
ajax="false"
immediate="true"/>
- В методе bean
doStuff
получить параметры с помощью имени фрагмента couse перед именем ввода 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 ;)
}