JSF2 + IceFaces 2 - Получить UIComponent из ViewRoot - PullRequest
0 голосов
/ 09 декабря 2011

Мне трудно решить следующее. Моя проблема довольно проста: я хотел бы выделить красным цветом поля форм, которые вызвали ошибки проверки. Сообщения об ошибках правильно размещаются в FacesContext с использованием строки context.addMessage (...).

Я бы хотел, чтобы моя система была универсальной. Все поля формы, к которым прикреплено сообщение, автоматически подсвечиваются.

Я нашел на этом сайте ссылку на эту прекрасную статью: http://www.jroller.com/mert/entry/how_to_find_a_uicomponent

С его помощью я реализовал PhaseListener для фазы RENDER_RESPONSE, который выполняет следующее:

@Override
  public void beforePhase(PhaseEvent event) {
    // get context
    FacesContext context = event.getFacesContext();

    // iterate on all the clientIds which have messages
    Iterator<String> clientIdsWithMessages = context.getClientIdsWithMessages();
    while (clientIdsWithMessages.hasNext()) {

      // get the clientId for the field component
      String clientIdWithMessage = clientIdsWithMessages.next();
      // split on ":"
      String[] splitted = clientIdWithMessage.split(":");

      UIComponent component = findComponentInRoot(splitted[splitted.length - 1]);
      if (component != null) {
        Map<String, Object> attributes = component.getAttributes();

        if (attributes.containsKey("style")) {
          attributes.remove("style");
        }
        attributes.put("style", "background-color: #FFE1E1;");
      }
    }
  }

Это прекрасно работает почти для всех моих использования.

Теперь, когда становится немного сложнее, некоторые из моих форм имеют такой код:

<ice:dataTable id="revisionDocuments" value="#{agendaBean.agenda.revisionsDocuments}" var="revision">
    <ice:column>
        <ice:inputText value="#{revision.sequenceAdresse}" id="revisionSequenceAdresse" />
    </ice:column>
    ....

Сгенерированная форма имеет несколько строк (по одной для каждого объекта списка revisionsDocuments), и каждый элемент имеет уникальный идентификатор (clientId), который выглядит следующим образом:

contentForm:revisionDocuments:0:revisionSequenceAdresse

С изменением 0 на 1, 2, ... для каждой итерации. Следовательно, код, предоставленный для поиска UIComponent из ViewRoot, не работает должным образом. Все поля формы имеют одинаковый идентификатор. Что меня больше удивляет, так это: у них одинаковый «clientId» в FacesContext:

contentForm:revisionDocuments:revisionSequenceAdresse

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

У кого-нибудь есть подсказка, чтобы решить это? Или еще одно предложение реализовать изюминку моих полей? Я должен признать, что мне не очень нравится мой код, я считаю грязным манипулировать viewRoot, как я делаю, но я не мог найти лучшего решения, чтобы иметь общее выделение моих полей.

Я использую IceFaces 2.0.2 с JSF-Impl 2.1.1-b04 на JBOss AS 7.0.2.Final.

Заранее спасибо за ответы. С наилучшими пожеланиями, Patrick

Ответы [ 2 ]

2 голосов
/ 09 декабря 2011

Вместо этого вы должны применить это на стороне клиента. У вас есть коллекция идентификаторов клиентов с сообщениями. Один из способов - передать эту информацию в JavaScript и позволить ей выполнить свою работу. Вы можете найти пример такого PhaseListener в этой статье: Установите фокус и выделите в JSF .

Начиная с JSF 2.0, существует другой способ без PhaseListener. Появилась новая неявная переменная EL #{component}, которая ссылается на экземпляр UIComponent текущего компонента. В случае компонентов UIInput существует метод isValid(). Это позволяет вам сделать что-то вроде:

<h:inputText styleClass="#{component.valid ? '' : 'error'}" />

с этим в файле CSS:

.error {
    background: #ffe1e1;
}

(да, вы также можете сделать это в атрибуте style, но стиль смешивания с разметкой - плохая практика)

Чтобы абстрагировать это (чтобы вам не нужно было повторять это при каждом входе), вы можете просто создать для этого составной компонент , что-то вроде <my:input>.

0 голосов
/ 16 декабря 2011

Для полноты, вот решение, которое я наконец нашел, чтобы выделить поля, которые имеют сообщения об ошибках с IceFaces 2.0.2:

Основная идея строго совпадает с предложенной BalusC на http://balusc.blogspot.com/2007/12/set-focus-in-jsf.html

Часть кода, которую мне пришлось изменить с помощью IceFaces, - это небольшой вызов Javascript:

<script>
    setHighlight('${highlight}');
</script>

Я не смог найти ни одного компонента IceFaces, который перерисовывается при каждом вызове JS. Я обнаружил, что размещение сценария в PanelGroup работает большую часть времени. Однако был случай, который не работал:

отправка формы с ошибками вызывает JS. затем повторная отправка формы с ошибками в том же поле, что и предыдущая проверка, НЕ запускает JS. затем повторная отправка формы с любым полем ошибок, в котором больше нет ошибок, вызывает JS. затем, повторно отправив форму с любым ошибочным полем, имеющим ошибку, запустите JS.

По какой-то причине IceFaces не отображает PanelGroup, которая содержит JS, когда набор полей с ошибками одинаков между двумя вызовами.

Я пытался использовать Javascript API с кодом, подобным Ice.onAsynchronousReceive (), используя библиотеку Prototype, чтобы прикрепить событие к завершению AJAX commandButton, но не добился большого успеха. Некоторые из моих тестов могли выполняться (с ошибками, но выполнили свою работу), и я мог наблюдать подобное поведение.

Вот трюк, который я наконец-то использовал (безобразно, но работает):

<ice:panelGroup>
    <script type="text/javascript">
        var useless = '#{testBean.time}';
        setHighlight('${highlight}');
    </script>
</ice:panelGroup>

Функция getTime () просто возвращает текущую метку времени. Тогда значение всегда отличается и запускает выполнение JS при любом запросе AJAX.

К сожалению, IceFaces не имеет полезного атрибута «oncomplete» RichFaces, о котором я очень сожалею в этом случае.

Гадкое решение, но забавное и работающее.

...