ajax - 如何找出ajax更新/渲染組件的客戶端ID? 找不到帶有“bar”引用的表達式“foo”的組件




2 Answers

在HTML輸出中查找實際的客戶端ID

您需要查看生成的HTML輸出以找出正確的客戶端ID。 在瀏覽器中打開該頁面,執行右鍵單擊並查看源代碼 。 找到感興趣的JSF組件的HTML表示並將其id作為客戶端ID。 您可以根據當前的命名容器以絕對或相對的方式使用它。 請參閱以下章節。

注意:如果它恰好包含像:0::1:等迭代索引(因為它位於迭代組件內),那麼您需要認識到並不總是支持更新特定迭代輪次。 請參閱答案底部以獲取更多詳細信息。

記住NamingContainer組件並始終為它們提供固定ID

如果您希望通過ajax process / execute / update / render引用的組件位於同一個NamingContainer父級中,則只需引用其自己的ID。

<h:form id="form">
    <p:commandLink update="result"> <!-- OK! -->
    <h:panelGroup id="result" />
</h:form>

如果它不在同一個NamingContainer ,那麼您需要使用絕對客戶端ID來引用它。 絕對客戶端ID以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輸出,他們的ID將預先添加到所有子組件的生成客戶端ID。 請注意,如果它們沒有固定ID,則JSF將使用j_idXXX格式的自動生成的ID。 你應該通過給他們一個固定的ID來完全避免這種情況。 在開發過程中, OmniFaces NoAutoGeneratedIdViewHandler可能會對此有所幫助。

如果你知道要找到UIComponent的javadoc,那麼你也可以在那裡檢查它是否實現了NamingContainer接口。 例如, HtmlForm<h:form>標籤後面的UIComponent )顯示它實現了NamingContainer ,但HtmlPanelGroup<h:panelGroup>標籤後面的UIComponent )沒有顯示它,所以它沒有實現NamingContainer這裡是所有標準組件 的javadoc,這裡是PrimeFaces的javadoc

解決你的問題

所以在你的情況下:

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

生成的<h:panelGrid id="display"> HTML輸出如下所示:

<table id="tabs:insTable:display">

您需要將該id完全作為客戶端ID,然後添加前綴:用於update

<p:commandLink update=":tabs:insTable:display">

在include / tagfile / composite之外引用

如果此命令鏈接位於include / tagfile中,且目標位於其外部,因此您不必知道當前命名容器的命名容器父項的ID,則可以通過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">

另請參閱獲取渲染/更新屬性中模板中父命名容器的標識

它如何在封面下工作

這一切在UIComponent#findComponent() javadoc中被指定為“搜索表達式”

搜索表達式由一個標識符(與UIComponent的id屬性完全匹配,或者由UINamingContainer#getSeparatorChar字符值鏈接的一系列這樣的標識符組成)。搜索算法應該如下操作,儘管可以使用替代算法只要最終的結果是一樣的:

  • 通過在滿足以下條件之一時立即停止,確定將作為搜索基礎的UIComponent
    • 如果搜索表達式以分隔符(稱為“絕對”搜索表達式)開頭,則基數將是組件樹的根UIComponent 。 前面的分隔符將被刪除,並且搜索表達式的其餘部分將被視為如下所述的“相對”搜索表達式。
    • 否則,如果這個UIComponent是一個NamingContainer ,它將作為基礎。
    • 否則,搜索此組件的父項。 如果遇到NamingContainer ,它將成為基礎。
    • 否則(如果沒有遇到NamingContainer ),根UIComponent將成為基礎。
  • 搜索表達式(可能在前一步中修改)現在是一個“相對”搜索表達式,它將用於在基本組件的範圍內定位具有匹配id的組件(如果有)。 比賽執行如下:
    • 如果搜索表達式是一個簡單的標識符,則將該值與id屬性進行比較,然後通過基礎UIComponent的構面和子元素遞歸地進行比較(除非如果找到後代NamingContainer ,則不搜索其自己的構面和子項)。
    • 如果搜索表達式包含多個由分隔符分隔的標識符,則使用第一個標識符按前一個項目符號點中的規則定位NamingContainer 。 然後,將調用此NamingContainerfindComponent()方法,傳遞搜索表達式的其餘部分。

請注意,PrimeFaces也遵守JSF規範,但RichFaces使用“一些額外的例外”

“reRender”使用UIComponent.findComponent()算法(以及其他一些例外)來查找組件樹中的組件。

這些額外的例外情況沒有詳細描述,但已知相關組件ID(即不以......開始的那些)不僅在最接近的父NamingContainer的上下文中搜索,而且在同一視圖中的所有其他NamingContainer組件中搜索(其是這樣一個相對昂貴的工作)。

切勿使用prependId="false"

如果這一切仍然無效,請驗證您是否使用<h:form prependId="false"> 。 這將在處理ajax提交和呈現過程中失敗。 另請參閱以下相關問題: 帶prependId =“false”的UIForm會打破<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開始支持它(它只是停止驗證它;因此你將永遠不會面對提到的異常中的問題;另一個增強的修補程序將在以後計劃)。

這只在當前的MyFaces 2.2.7和PrimeFaces 5.2版本中不起作用。 未來的版本可能會提供支持。 與此同時,你最好的選擇是更新迭代組件本身,或者是一個父母,以防止它不呈現HTML,比如<ui:repeat>

使用PrimeFaces時,請考慮搜索表達式或選擇器

PrimeFaces搜索表達式允許您通過JSF組件樹搜索表達式來引用組件。 JSF有幾個內置的:

  • @this :當前組件
  • UIForm :父UIForm
  • @all :整個文檔
  • @none :什麼都沒有

PrimeFaces通過新的關鍵字和復合表達式支持增強了這一點:

  • @parent :父組件
  • @namingcontainer :父級UINamingContainer
  • @widgetVar(name) :由給定的widgetVar標識的widgetVar

您還可以在復合表達式中混合這些關鍵字,例如@this:@parent:@parent @form:@parent@form:@parent @this:@parent:@parent等。

@(.someclass) PrimeFaces選擇器(PFS)允許您通過jQuery CSS選擇器語法來引用組件。 例如,在HTML輸出中引用具有所有常見樣式類的組件。 如果您需要參考“許多”組件,這特別有用。 這只要求目標組件在HTML輸出中具有所有客戶端ID(固定或自動生成,無關緊要)。 另請參見PrimeFaces選擇器如何在update =“@(。myClass)”中工作?

下面的代碼受PrimeFaces DataGrid + DataTable教程的啟發,並放置在駐留在<p:layoutUnit><p:tabView>中的<p:layoutUnit><p:layoutUnit>中。 這裡是代碼的內部部分(從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> ,代碼停止工作並給出消息:

從“tabs:insTable:select”引用的表達式“insTable:display”找不到組件。

當我使用<f:ajax>進行相同的嘗試時,它會失敗,並顯示一條基本上不同的消息:

<f:ajax>包含未知ID“insTable:display”無法在組件的上下文中找到它“選項卡:insTable:select”

這是如何造成的,我該如何解決這個問題?




這是因為該選項卡是一個命名容器以及...你的更新應該是update="Search:insTable:display"你可以做的也只是把你的對話框放在窗體外面,然後仍然是: update="Search:display"




Related

ajax jsf jsf-2 primefaces clientid