JSF пропускает обязательную проверку без немедленного = истина

У меня есть несколько форм, в которых есть обязательные и необязательные поля.

Чтобы отправить такую ​​форму, мне требуется выполнить проверку требуемого атрибута, что работает нормально. Чтобы отменить такую ​​форму, я использую атрибут immediate="true" в p:commandbutton, что приводит к его действию на этапе Apply Request Values, как описано здесь: Как пропустить проверку при нажатии определенной кнопки?

Однако для больших форм я хочу предоставить пользователю кнопку «Сохранить», чтобы он мог продолжить позже.

Просто для сохранения текущего состояния я также хочу игнорировать проверку обязательного атрибута. Однако использование immediate="true" не работает, потому что тогда мой простой метод сохранения ничего не сохраняет, потому что жизненный цикл JSF никогда не достигает фазы «UpdateModelValues». (Согласно http://www.javacodegeeks.com/2012/01/jsf-and-immediate-attribute-command.html )

Итак, как обойти требуемую проверку, но не пропустить половину жизненного цикла?


person dognose    schedule 15.01.2013    source источник
comment
Учитывая ответ, технически это обман Как сделать так, чтобы проверка зависела от нажатой кнопки?.   -  person BalusC    schedule 11.08.2015
comment
@BalusC Вы правы, но другой вопрос касается точной технической детали. Этот я создал, когда еще не был так хорошо знаком со всеми формулировками JSF (сегодня я его немного поправил), и поэтому он идеально соответствует соответствующему поиску в Google, который новичок мог бы отправить: google.de/ (однако оба имеют высокий рейтинг)   -  person dognose    schedule 11.08.2015


Ответы (6)


Каждая кнопка создает запись внутри списка параметров, если она является членом формы. Поэтому я просто применил проверку наличия этой записи к «обязательному» параметру:

<h:form id="form" prependId="true">
...
<p:inputText id="someId"
    required="#{param['form:save']==null}" ... />
...
<p:commandButton id="save" value="Save" />
<p:commandButton id="submit" value="Submit" />
<p:commandButton id="cancel" value="Cancel" immediate="true" />
</h:form>

Когда я нажимаю «Отправить», param['form:save'] становится NULL, что затем превращает выражение в true, поэтому проверка выполняется.

Когда я нажимаю «Сохранить», param['form:save'] становится NOT NULL (но пустым!), который разрешается в false, поэтому проверка игнорируется. (Или, скажем, JSF считает, что это не обязательное поле из-за того, что выражение оценивается как false)

person dognose    schedule 15.01.2013
comment
на примечании: true and здесь явно НЕ требуется;) - person dognose; 15.01.2013
comment
@BalusC Я использую Primefaces. Не уверен, что есть что-то равное. (пока не нашел) - person dognose; 15.01.2013
comment
Отличная работа! фантастика. После 3 часов сумасшествия я нашел ваш ответ. Очень круто! - person 98percentmonkey; 27.11.2014
comment
Он также работает с компонентами BootsFaces. Убедитесь, что ajax=true. Не работает с <h:inputText> и <f:ajax>. См. stackoverflow.com /questions/29882417/ для получения дополнительной информации. - person alexander; 25.07.2015
comment
Я не думаю, что это отличный пользовательский интерфейс, потому что * в обязательных полях будет отображаться только тогда, когда пользователь нажимает «Отправить» или «Отмена». Есть ли другой способ сделать это, чтобы требуемый * появлялся все время? - person Erick; 30.09.2018
comment
@Erick Просто создайте * с меткой, которая содержит обычное обязательное условие. - person dognose; 08.10.2018

Это отличный вопрос и очень полезный ответ. Такой подход избавляет от многих проблем с immediate="true".

Я хотел бы добавить эту информацию (но мне пока не разрешено комментировать). Для ваших примеров кода требуется JSF 2.0 или выше (поправьте меня). Если вы, как и я, прокляты использовать JSF 1.1/1.2, рассмотрите эти изменения/дополнения:

<h:form id="form">
...
<p:inputText id="someId" required="#{!empty param['save']}" ... />
...
<p:commandButton id="save" value="Save" />
</h:form>
  • В JSF 1.1 нет атрибута prependId
  • Поэтому в param[...] нужно указать только id кнопки
  • Вы используете синтаксис ="{true and ...}", который может быть ошибкой (без #)?
  • Как вы можете видеть из собственной истории редактирования, логика "null or not null" не очень интуитивна :) Поэтому мне сразу понравилась !empty ... версия, когда я наткнулся на нее.
person SebastianH    schedule 29.01.2014
comment
{true and ...} отсутствует #, это правильно. и правда устарела. Он существует, потому что мы генерируем все наши формы автоматически (во время разработки) и имеем возможность определить, требуется ли что-то или нет. Затем, если форма позволяет сохранить, мы просто добавили проверку параметров. И поскольку вы правы — нулевое значение не очень интуитивно понятно, мы решили оставить исходное значение (true или false) вместе с этой проверкой для лучшей читабельности. - person dognose; 30.01.2014
comment
JSF 1.1 по умолчанию добавляет идентификатор клиента формы. Так что вы все равно должны использовать form:save. Я не уверен, почему dognose явно объявил prependId="true", поскольку это уже значение по умолчанию. - person BalusC; 30.01.2014
comment
@BalusC Я пробовал это, но у меня это не работает. Если я использую required="#{!empty param['save']}", я получаю предполагаемые ошибки проверки при публикации наполовину заполненной формы. Если вместо этого я использую required="#{!empty param['form:save']}", проверка не происходит - и я получаю много ошибок базы данных;). - person SebastianH; 30.01.2014
comment
Правильно, вы используете обычный HTML <form> вместо JSF <h:form>. - person BalusC; 30.01.2014
comment
На самом деле я не знаю. Я использую <h:form>. Приведенный выше пример был основан на догнозах. - person SebastianH; 30.01.2014
comment
Ответ неверный. Решение зависит от тонкой разницы между null и пустой строкой. оператор EL empty видит эту тонкую разницу, и оба будут оценивать true. Это уже обсуждалось @BalusC ранее. Решение состоит в том, чтобы явно проверить == null, как в другом ответе. - person YoYo; 28.07.2017

если вы хотите пропустить проверку при нажатии на кнопку, просто добавьте параметр к кнопке, где вы хотите ее пропустить. Пример:

<p:commandButton value="button1" action="#{bean.action()}" >
   <f:param name="skipValidator" value="true"/>
</p:commandButton>

Затем в валидаторе вы можете прочитать этот параметр и, если он верен, то пропустить его:

@FacesValidator("com.validators.MyValidator")
public class MyValidator implements Validator{

  public void validate(FacesContext ct, UIComponent co, Object obj) throws ValidatorException { 
    if(!continueValidation()){
      return;
    }
    // validation process
  }

protected boolean continueValidation() {
    String skipValidator= FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("skipValidator");
    if (skipValidator != null && skipValidator.equalsIgnoreCase("true")) {
      return false;
    }
    return true;
  } 
}
person Juraj    schedule 12.02.2015
comment
Этот подход не пропускает стандартные значения модели обновления жизненного цикла, но пропускает FacesValidator. Полезно для кнопки «Очистить». Тнк человек. - person aspadacio; 21.08.2017

Альтернативой тому, что предлагали другие, является использование пользовательского BeanValidator, который будет проверять форму, если, скажем, нажал кнопку с сохранением идентификатора. Любая другая кнопка, не определенная неявно для выполнения проверки, не будет проверять, а просто отправит доступные данные. Полный красивый и чистый пример можно найти здесь< /а>

person Given Nyauyanga    schedule 03.05.2016

Я использую skipValidators для такого случая (при условии, что все проверки пропущены). Код из omnifaces

<h:form>
  <h:dataTable value="#{bean.items}" var="item">
    <h:column>
        <h:inputText value="#{item.value}" required="true" />
    </h:column>
  </h:dataTable>
  <h:commandButton value="add new row" action="#{bean.add}">
    <o:skipValidators />
  </h:commandButton>
  <h:commandButton value="save all data" action="#{bean.save}" />
  <h:messages />
</h:form>
person dr0ps    schedule 04.01.2019

В моем случае я не нашел clientId кнопки в параметрах, но нашел этот param['javax.faces.source'] = buttonClientId в карте запросов. Значением будет clientId нажатой кнопки.

person Shady Hussein    schedule 22.12.2014