Как узнать идентификатор клиента компонента для ajax update / render? Не удается найти компонент с выражением "foo", на который ссылается " bar"



следующий код вдохновлен учебниками PrimeFaces DataGrid + DataTable и помещен в <p:tab> на <p:tabView> проживающего в <p:layoutUnit> на <p:layout>. Вот внутренняя часть кода (начиная с p:tab компонент); внешняя часть тривиальна.



<p:tabView id="tabs">
<p:tab id="search" title="Search">
<h:form id="insTable">
<p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}">
<p:column>
<p:commandLink id="select" update="insTable:display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog id="dlg" modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
</h:form>
</p:tab>
</p:tabView>


когда я нажимаю <p:commandLink>, код перестает работать и выдает сообщение:




не удается найти компонент с выражением "нестабильная:дисплей" ссылается "вкладки: нестабильный: выберите".




когда я пытаюсь то же самое с помощью <f:ajax>, он терпит неудачу с другим сообщением, в основном говорящим то же самое:




<f:ajax> содержит неизвестный идентификатор "insTable: display" не удается найти его в контексте компонента "вкладки: insTable: select"




как это вызвано и как я могу решить это?

688   4  

4 ответов:

посмотрите в выводе HTML для фактического идентификатора клиента

вам нужно посмотреть в сгенерированном выводе HTML, чтобы узнать правильный идентификатор клиента. Откройте страницу в браузере, сделайте правый клик и Посмотреть Источник. Найдите HTML-представление интересующего компонента JSF и возьмите его id как идентификатор клиента. Вы можете использовать его в абсолютном или относительном виде в зависимости от текущего контейнера именования. См. следующую главу.

Примечание: если он содержит индекс итерации как :0:,:1: и т. д. (поскольку он находится внутри итерационного компонента), вам нужно понять, что обновление определенного цикла итерации не всегда поддерживается. См. нижнюю часть ответа для более подробной информации об этом.

запомнить NamingContainer компоненты и всегда дают им фиксированный код

если компонент, на который вы хотите ссылаться с помощью ajax process / execute/update / render, находится внутри того же NamingContainer родитель, то просто ссылаться на свой собственный ИДЕНТИФИКАТОР.

<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> (таким образом, все составные компоненты), etc. Вы легко узнаете их по сгенерированный вывод HTML, их идентификатор будет добавлен к сгенерированному идентификатору клиента всех дочерних компонентов. Обратите внимание, что если у них нет фиксированного идентификатора, то JSF будет использовать автогенерированный идентификатор в . Вы должны абсолютно избежать этого, предоставив им фиксированный идентификатор. Элемент OmniFaces NoAutoGeneratedIdViewHandler может быть полезно в этом во время разработки.

если вы знаете, чтобы найти javadoc из UIComponent в вопросе, то вы также можете просто проверить там ли он реализует NamingContainer интерфейс или нет. Например,HtmlForm (the UIComponent за <h:form> tag) показывает, что он реализует NamingContainer, а HtmlPanelGroup (the UIComponent за <h:panelGroup> tag) не показывает его, поэтому он не реализует 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">

ссылки вне include / 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">

см. также получить идентификатор родительского контейнера именования в шаблоне для атрибута in render / update

как это работает под обложки

это все указано как "поиск выражения" на the UIComponent#findComponent() документация:

A выражение поиска состоит из любого идентификатора (который точно соответствует свойству id a UIComponent, или ряд таких идентификаторов, связанных с помощью UINamingContainer#getSeparatorChar значение символа. Поиск алгоритма работает следующим образом, хотя альтернативный alogrithms может быть использована как конечный результат то же самое:

  • определение 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 .

ссылка на конкретный итерационный раунд итерационных компонентов

долгое время не было возможности ссылаться на конкретный итерационный элемент в итерации такие компоненты, как <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 the <f:ajax> начал поддерживать его (он просто перестал проверять его; таким образом, вы больше никогда не столкнетесь с упомянутым исключением в вопросе; для этого позже планируется другое исправление улучшения).

это только еще не работает в текущих версиях MyFaces 2.2.7 и PrimeFaces 5.2. Поддержка может появиться в будущих версиях. В то же время, ваш лучший выбор, чтобы обновить сам итерационный компонент или родитель в случае, если он не отображает HTML, например <ui:repeat>.

при использовании PrimeFaces следует учитывать поисковые выражения или селекторы

PrimeFaces Search Expressions позволяет ссылаться на компоненты с помощью выражений поиска дерева компонентов JSF. В JSF имеет несколько встроенных:

  • @this: текущий компонент
  • @form родитель UIForm
  • @all: весь документ
  • @none: ничего

PrimeFaces улучшил это с помощью новых ключевых слов и поддержки составных выражений:

  • @parent: родительский компонент
  • @namingcontainer родитель UINamingContainer
  • @widgetVar(name): компонент, идентифицированный заданным widgetVar

вы также можете смешивать эти ключевые слова в составных выражениях, таких как @form:@parent,@this:@parent:@parent, так далее.

селекторы PrimeFaces (PFS) а в @(.someclass) позволяет ссылаться на компоненты с помощью синтаксиса селектора jQuery CSS. Например, ссылки на компоненты, имеющие все общий класс стиля в выводе HTML. Это особенно полезно в случае, если вам нужно ссылаться на "много" компонентов. Это только предварительно требует, чтобы все целевые компоненты имели идентификатор клиента в выводе HTML (фиксированный или автогенерированный, не имеет значения). Смотрите также как сделать селекторы PrimeFaces, как в обновление.(@"=myClass) " работа?

прежде всего: насколько я знаю, размещение диалога внутри tabview-это плохая практика... тебе лучше его вытащить...

а теперь к вашему вопросу:

к сожалению, мне потребовалось некоторое время, чтобы получить то, что именно вы хотели реализовать,

сделал в моем веб-приложении себя только сейчас, и это работает

Как я говорил раньше поместите P: диалог вне стороны ' p: tabView,

оставьте P: диалоговое окно, как вы изначально предложили:

<p:dialog modal="true" widgetVar="dlg">
    <h:panelGrid id="display">
        <h:outputText value="Name:" />
        <h:outputText value="#{instrumentBean.selectedInstrument.name}" />
    </h:panelGrid>
</p:dialog>   

и p: commandlink должен выглядеть так (все, что я сделал, это изменить атрибут обновления)

<p:commandLink update="display" oncomplete="dlg.show()">
    <f:setPropertyActionListener value="#{lndInstrument}" 
        target="#{instrumentBean.selectedInstrument}" />
    <h:outputText value="#{lndInstrument.name}" />
</p:commandLink>  

то же самое работает в моем веб-приложении, и если это не работает для вас , то я думаю, что что-то не так в вашем коде Java bean...

это потому, что вкладка также является контейнером именования... обновление должно быть update="Search:insTable:display" Что вы можете сделать, так это просто разместить свой диалог вне формы и все еще внутри вкладки, тогда это будет:update="Search:display"

попробуйте изменить update="insTable:display" до update="display". Я считаю, что вы не можете префикс id с идентификатором формы, как это.

Comments

    Ничего не найдено.