Ответ 1
Посмотрите в выводе HTML для фактического идентификатора клиента
Вам нужно посмотреть в сгенерированном HTML-выводе, чтобы узнать правильный идентификатор клиента. Откройте страницу в браузере, сделайте правый щелчок и просмотрите источник. Найдите HTML-представление интересующего компонента JSF и введите id
в качестве идентификатора клиента. Вы можете использовать его в абсолютном или относительном режиме в зависимости от текущего контейнера именования. См. Следующую главу.
Примечание: если он содержит индекс итерации, такой как :0:
, :1:
и т.д. (потому что он внутри итерационного компонента), то вам нужно понять, что обновление определенного раунда итераций не всегда поддерживается. См. Нижнюю часть ответа для получения более подробной информации об этом.
Запоминать компоненты NamingContainer
и всегда предоставлять им фиксированный идентификатор
Если компонент, который вы хотите ссылаться с помощью ajax process/execute/update/render, находится внутри того же NamingContainer
parent, затем просто укажите свой собственный идентификатор.
<h:form id="form">
<p:commandLink update="result"> <!-- OK! -->
<h:panelGroup id="result" />
</h:form>
Если он не внутри одного и того же NamingContainer
, вам нужно ссылаться на него с использованием абсолютного идентификатора клиента. Абсолютный идентификатор клиента начинается с символа разделителя NamingContainer
, который по умолчанию :
.
<h:form id="form">
<p:commandLink update="result"> <!-- FAIL! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
<p:commandLink update=":result"> <!-- OK! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
<p:commandLink update=":result"> <!-- FAIL! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
<h:form id="form">
<p:commandLink update=":otherform:result"> <!-- OK! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
NamingContainer
являются, например, <h:form>
, <h:dataTable>
, <p:tabView>
, <cc:implementation>
(таким образом, все составные компоненты ) и т.д. Вы легко узнаете их, глядя на сгенерированный вывод HTML, их идентификатор будет добавлен к сгенерированному идентификатору клиента всех дочерних компонентов. Обратите внимание, что когда у них нет фиксированного идентификатора, JSF будет использовать автогенерированный идентификатор в формате j_idXXX
. Вы должны избегать этого, указав им фиксированный идентификатор. OmniFaces NoAutoGeneratedIdViewHandler
может быть полезен при этом во время разработки.
Если вы знаете, чтобы найти javadoc из UIComponent
, о котором идет речь, вы также можете просто проверить там, реализует ли он NamingContainer
или нет. Например, HtmlForm
(тег UIComponent
за тегом <h:form>
) показывает, что он реализует NamingContainer
, но HtmlPanelGroup
(тег UIComponent
за тегом <h:panelGroup>
) не отображает его, поэтому он не реализует NamingContainer
. Вот javadoc всех стандартных компонентов и вот javadoc из PrimeFaces.
Решение проблемы
Итак, в вашем случае:
<p:tabView id="tabs"><!-- This is a NamingContainer -->
<p:tab id="search"><!-- This is NOT a NamingContainer -->
<h:form id="insTable"><!-- This is a NamingContainer -->
<p:dialog id="dlg"><!-- This is NOT a NamingContainer -->
<h:panelGrid id="display">
Сгенерированный вывод HTML <h:panelGrid id="display">
выглядит следующим образом:
<table id="tabs:insTable:display">
Вам нужно взять именно это id
как идентификатор клиента, а затем префикс с :
для использования в update
:
<p:commandLink update=":tabs:insTable:display">
Ссылка снаружи включает /tagfile/composite
Если эта командная ссылка находится внутри файла include/tagfile, а цель находится за ее пределами, и, следовательно, вы не обязательно знаете идентификатор родителя контейнера именования текущего контейнера именования, тогда вы можете динамически ссылаться на него через UIComponent#getNamingContainer()
так:
<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">
Или, если эта командная ссылка находится внутри составного компонента, а цель находится вне нее:
<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">
Или, если и командная ссылка, и цель находятся внутри одного составного компонента:
<p:commandLink update=":#{cc.clientId}:display">
См. также Получить идентификатор родительского контейнера именования в шаблоне для атрибута render/update
Как это работает под обложками
Это все указано как "выражение поиска" в UIComponent#findComponent()
javadoc:
Выражение поиска состоит из либо идентификатора (который точно совпадает с идентификатором id
UIComponent
, так и серией таких идентификаторов, связанных символьным значениемUINamingContainer#getSeparatorChar
). Алгоритм поиска должен действовать следующим образом альтернативные алограммы могут использоваться до тех пор, пока конечный результат не будет таким:
- Определите
UIComponent
, который будет базой для поиска, остановив, как только будет выполнено одно из следующих условий:
- Если выражение поиска начинается с символа разделителя (называемого "абсолютным" поисковым выражением), базой будет корень
UIComponent
дерева компонентов. Ведущий символ разделителя будет удален, а остаток выражения поиска будет рассматриваться как "относительное" выражение поиска, как описано ниже.- В противном случае, если этот
UIComponent
являетсяNamingContainer
, он будет служить в качестве основы.- В противном случае выполните поиск родителей этого компонента. Если встречается a
NamingContainer
, это будет база.- В противном случае (если нет
NamingContainer
) кореньUIComponent
будет базой.- Выражение поиска (возможно, измененное на предыдущем шаге) теперь является "относительным" поисковым выражением, которое будет использоваться для поиска компонента (если есть), который имеет идентификатор, который соответствует в рамках базового компонента. Матч выполняется следующим образом:
- Если выражение поиска является простым идентификатором, это значение сравнивается с свойством id, а затем рекурсивно через грани и дочерние элементы базы
UIComponent
(за исключением того, что если найденный потомокNamingContainer
найден, его собственные грани и детей не обыскали).- Если выражение поиска содержит более одного идентификатора, разделенного символом-разделителем, первый идентификатор используется для определения местоположения
NamingContainer
по правилам предыдущей маркерной точки. Затем будет вызываться методfindComponent()
этогоNamingContainer
, передающий остальную часть поискового выражения.
Обратите внимание, что PrimeFaces также придерживается спецификации JSF, но RichFaces использует "некоторые дополнительные исключения" .
"reRender" использует алгоритм
UIComponent.findComponent()
(с некоторыми дополнительными исключениями), чтобы найти компонент в дереве компонентов.
Эти дополнительные исключения нигде подробно не описаны, но известно, что относительные идентификаторы компонентов (т.е. те, которые не начинаются с :
), не только просматриваются в контексте ближайшего родителя NamingContainer
, но также и во всех остальных NamingContainer
в одном представлении (что, кстати, относительно дорогостоящее задание).
Никогда не используйте prependId="false"
Если это все еще не работает, проверьте, не используете ли вы <h:form prependId="false">
. Это не удастся при обработке ajax submit и render. См. Также этот связанный вопрос: UIForm с prependId = "false" breaks < f: ajax render > .
Ссылка на конкретную итерацию раунда итерирующих компонентов
В течение долгого времени невозможно было ссылаться на конкретный итерированный элемент при итерации таких компонентов, как <ui:repeat>
и <h:dataTable>
, например:
<h:form id="form">
<ui:repeat id="list" value="#{['one','two','three']}" var="item">
<h:outputText id="item" value="#{item}" /><br/>
</ui:repeat>
<h:commandButton value="Update second item">
<f:ajax render=":form:list:1:item" />
</h:commandButton>
</h:form>
Однако, поскольку Mojarra 2.2.5 <f:ajax>
начал поддерживать его (он просто прекратил проверку его, таким образом, вы больше никогда не столкнетесь с вопросом в упомянутом исключении, другое исправление исправления планируется для этого позже).
Это все еще не работает в текущих версиях MyFaces 2.2.7 и PrimeFaces 5.2. Поддержка может появиться в будущих версиях. В то же время лучше всего обновить итерирующий компонент самостоятельно или родительский, если он не отображает HTML, например <ui:repeat>
.
При использовании PrimeFaces рассмотрите поисковые выражения или селектора
PrimeFaces Search Expressions позволяет ссылаться на компоненты через выражения поиска дерева компонентов JSF. JSF имеет несколько встроенных функций:
-
@this
: текущий компонент -
@form
: parentUIForm
-
@all
: весь документ -
@none
: ничего
PrimeFaces улучшил это с помощью новых ключевых слов и поддержки композитных выражений:
-
@parent
: родительский компонент -
@namingcontainer
: parentUINamingContainer
-
@widgetVar(name)
: компонент, идентифицированный даннымwidgetVar
Вы также можете смешивать эти ключевые слова в составных выражениях, таких как @form:@parent
, @this:@parent:@parent
и т.д.
PrimeFaces Selectors (PFS), как в @(.someclass)
, позволяет вам ссылаться на компоненты с помощью синтаксиса селектора CSS jQuery. Например. ссылающиеся на компоненты, имеющие общий класс стиля в HTML-выходе. Это особенно полезно, если вам нужно ссылаться на "множество" компонентов. Это требует только того, что целевые компоненты имеют все идентификатор клиента в выходном файле HTML (фиксированный или автогенерированный, не имеет значения). См. Также Как селектор PrimeFaces как в update = "@(. MyClass)" работать?