Установка атрибута валидатора с использованием EL на основе пользовательского интерфейса: repeat var - PullRequest
5 голосов
/ 08 февраля 2012

Сегодня я ищу немного советов по проблеме, с которой я сталкиваюсь.

То, что я пытаюсь сделать, - это создать страницу на лету с проверкой и прочим. Конечный результат - позволить пользователю настраивать поля на странице с помощью административных функций. Ниже приведена копия кода, который я использую в качестве тестовой страницы, где я перебираю поля «Настроенные» и выписываю поля, используя определенные критерии.

<ui:repeat var="field" value="#{eventMgmt.eventFields}" varStatus="status">
  <div class="formLabel">
    <h:outputLabel value="#{field.customName}:"></h:outputLabel>
  </div>
  <div class="formInput">
    <h:inputText id="inputField" style="width:# {field.fieldSize gt 0 ? field.fieldSize : 140}px;">
      <f:validateRegex  disabled="#{empty field.validationPattern}" pattern="#{field.validationPattern}"></f:validateRegex>
    </h:inputText>
    <h:message for="inputField" showDetail="true" errorClass="errorText"></h:message>
  </div>
</ui:repeat>

После того, как страница отображается и я пытаюсь отправить какие-либо значения для поля, я получаю следующее сообщение: «Для шаблона регулярного выражения должно быть установлено непустое значение». что, очевидно, означает, что выражение не заполнено. Что меня интересует, так это то, что поля, для которых нет выражения, будут отключены при оценке EL. Я также могу взять тот же код # {field.validationPattern} и поместить его на страницу, и правильное значение будет написано на странице.

Итак, мой вопрос (ы): 1. Возможно ли это? 2. В какой момент контейнер JSF смотрит на привязку шаблона для регулярного выражения проверки? 3. Что я делаю неправильно или как это правильно делать?

Я использую Tomcat 7.0.22, Mojarra 2.1.5 и Eclipse в качестве моей IDE.

1 Ответ

12 голосов
/ 08 февраля 2012

Это вызвано использованием <f:validateRegex>, свойства которого зависят от текущего итерированного элемента <ui:repeat>.

Теги <f:xxx> являются обработчиками тегов, а не компонентами пользовательского интерфейса.Обработчики тегов анализируются и оцениваются, когда дерево компонентов пользовательского интерфейса должно быть построено во время построения представления.Все EL оценивается во время сборки представления.Теги <h:xxx> и некоторые теги <ui:xxx>, такие как <ui:repeat>, являются компонентами пользовательского интерфейса.Все их EL оцениваются во время визуализации представления.

Таким образом, в вашем случае, когда <f:validateRegex> анализируется и выполняется, #{field} недоступен в текущей области видимости EL и, следовательно, оценивается как null.

Есть несколько способов заставить его работать.

  • Переместите валидатор в класс, представляющий Field, и сделайте ссылку на него следующим образом:

    <h:inputText ... validator="#{field.validate}" />
    

    с помощью класса Field, в котором вы вручную создадите его экземпляр:

    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        if (pattern != null) {
            RegexValidator regexValidator = new RegexValidator();
            regexValidator.setPattern(pattern);
            regexValidator.validate(context, component, value);
        }
    }
    

  • Или оберните #{eventMgmt.eventFields} в ListDataModel<Field> и привяжите валидатор к бобу #{eventMgmt}.Таким образом, вы сможете установить свойства валидатора на основе данных строки:

    <h:inputText ... validator="#{eventMgmt.validate}" />
    

    с классом базового компонента позади #{eventMgmt}:

    private DataModel<Field> model;
    private RegexValidator regexValidator;
    
    @PostConstruct
    public void init() {
        regexValidator = new RegexValidator();
    }
    
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        String pattern = model.getRowData().getPattern();
    
        if (pattern != null) {
            regexValidator.setPattern(pattern);
            regexValidator.validate(context, component, value);
        }
    }
    

  • Или создайте пользовательский Validator, который расширяет RegexValidator, и установите шаблон как пользовательский атрибут компонента с помощью <f:attribute>, и позвольте Validator перехватить это.<f:attribute> в основном добавляет новый компонент к компоненту с неоцененным ValueExpression, поэтому он будет переоценен при его вызове.Например:

    <h:inputText ...>
        <f:validator validatorId="extendedRegexValidator" />
        <f:attribute name="pattern" value="#{field.pattern}" />
    </h:inputText>
    

    с

    @FacesValidator("extendedRegexValidator")
    public class ExtendedRegexValidator extends RegexValidator {
    
        @Override
        public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
            String pattern = (String) component.getAttributes().get("pattern");
    
            if (pattern != null) {
                setPattern(pattern);
                super.validate(context, component, value);
            }
        }
    
    }
    

  • Или, если вам случится использовать служебную библиотеку JSF OmniFaces , используйте ее<o:validator>.Например,

    <h:inputText ...>
        <o:validator validatorId="javax.faces.RegularExpression" pattern="#{field.pattern}" />
    </h:inputText>
    

    Да, вот и все.<o:validator> обеспечит, чтобы все атрибуты оценивались как отложенные выражения вместо непосредственных выражений.

См. Также:

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