Подтвердить что ты не робот

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

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

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

<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>

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

_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 обрабатывает полные страницы, даже если они не включены и почему я получаю это исключение.

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

Я не хочу также обертывать каждую из страниц некоторым компонентом контейнера с другим идентификатором, поэтому у них будет другой FULL ID, такой как formId: fieldID, потому что главная страница также ссылается на эти компоненты внутри этих включает!

4b9b3361

Ответ 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 или новее, иначе просмотр области видимости beans будет вести себя как область с запросом beans.

Альтернативой является использование условного оператора 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} доступен во время сборки времени просмотра, а также то, что точно такое же значение доступно во время фазы просмотра восстановления postbacks, как это было во время первоначальной рендеринга, в противном случае представление возможно, будут восстановлены с неправильным включением, и JSF больше не сможет декодировать правильные входы и команду. Кроме того, если вы хотите изменить включение во время обратной передачи, вам действительно нужно перестроить представление (вернуть не null/void) или отправить перенаправление.

См. также: