Условное включение JSF, поскольку идентификатор компонента уже найден в представлении.

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

У меня есть страница, которая включает другие страницы по определенному условию. Вот так...

<h:panelGroup rendered="#{bean.insertMode == 'SINGLE'}">
   <ui:include src="_single.xhtml" />
</h:panelGroup> 
<h:panelGroup rendered="#{bean.insertMode == 'DOUBLE'}">
   <ui:include src="_double.xhtml" />
</h:panelGroup>

Теперь на этих страницах у меня есть «почти» одинаковая иерархия компонентов (комплекс) с различным поведением действий (не только вызовы методов, но и просмотр), например:

_single.xhtml

<p:inputText id="fieldID" value="#{bean.value}" />
<p:commandLink actionListener="#{bean.singleAction()}" />

_double.xhtml

<p:inputText id="fieldID" value="#{bean.value}" />
<p:commandLink actionListener="#{bean.doubleAction()}" />

Мой маленький пример работает нормально и отображается так, как должен, но я получаю

java.lang.IllegalStateException: Component ID fieldID has already been found in the view.

Я знаю, что JSF обрабатывает полные страницы, даже если они не включены, и поэтому я получаю это исключение.

Any smart way to solve this without changing the IDs of the components inside the include pages (Although it works, but the exception is annoying and seems something is wrong).

Я также не хочу обертывать каждую из страниц каким-либо компонентом-контейнером с другим идентификатором, чтобы у них был другой ПОЛНЫЙ идентификатор, например formId:fieldID, потому что главная страница также ссылается на эти компоненты внутри этих включений!


person Hatem Alimam    schedule 12.09.2013    source источник
comment
Если и файлы single.xhtml, и файлы double.xhtml содержат почти точную структуру, почему бы вместо этого не использовать одну страницу?   -  person Luiggi Mendoza    schedule 12.09.2013
comment
Это не точная структура ... она совершенно другая, с некоторыми общими полями среди них ... И я не хочу менять идентификаторы этих общих полей :) @LuiggiMendoza   -  person Hatem Alimam    schedule 12.09.2013
comment
Вы можете обернуть их невидимым NamingContainer на родительской странице или на дочерних страницах. Такой невидимый контейнер имен легко сделать с помощью составного компонента.   -  person rdcrng    schedule 12.09.2013
comment
@rdcrng Пожалуйста, прочитайте последний раздел моего поста :)   -  person Hatem Alimam    schedule 12.09.2013
comment
Да, поэтому я прокомментировал вместо ответа - я знал, что есть лучший способ, и я вижу, что BalusC уже указал на это :)   -  person rdcrng    schedule 12.09.2013


Ответы (1)


Ошибка повторяющегося идентификатора компонента возникает из-за того, что оба включения физически оказываются в дереве компонентов JSF. <h:panelGroup rendered="false"> не предотвращает их попадание в дерево компонентов JSF, вместо этого они не позволяют им генерировать вывод HTML.

Вместо условного рендеринга их вывода HTML вам необходимо условно построить их в дереве компонентов JSF. JSTL очень полезен в этом, поскольку он запускается во время сборки представления:

<c:if test="#{bean.insertMode eq 'SINGLE'}">
    <ui:include src="_single.xhtml" />
</c:if> 
<c:if test="#{bean.insertMode eq 'DOUBLE'}">
    <ui:include src="_double.xhtml" />
</c:if>

Если вы используете Mojarra, вам нужно только убедиться, что вы используете по крайней мере версию 2.1.18 или новее, иначе bean-компоненты с областью видимости будут вести себя как bean-компоненты с областью запроса.

Альтернативой является использование условного оператора EL в атрибуте src (сам <ui:include> работает как обработчик тегов также во время сборки представления):

<ui:include src="_#{bean.insertMode eq 'SINGLE' ? 'single' : 'double'}.xhtml" />

Или даже используйте insertMode непосредственно в качестве имени файла:

<ui:include src="_#{fn:toLowerCase(bean.insertMode)}.xhtml" />

В любом случае, вы должны быть абсолютно уверены, что #{bean.insertMode} доступно во время построения представления, а также, что точно такое же значение доступно на этапе восстановления представления обратных передач, как и при первоначальном рендеринге, иначе представление, возможно, будет восстановлено с помощью неправильное включение, и JSF больше не может декодировать правильные входные данные и команду. Кроме того, когда вы хотите изменить включение во время обратной передачи, вам действительно нужно перестроить представление (вернуть не-null/void) или отправить перенаправление.

Смотрите также:

person BalusC    schedule 12.09.2013
comment
Обновление с 2.1.2 до 2.1.18 спасло меня. - person Joergi; 21.04.2016
comment
@Joerg: Не за что. Обратите внимание, что версия 2.1.x в настоящее время уже имеет версию 2.1.29. - person BalusC; 21.04.2016