簡體   English   中英

如何實現 NamingContainer? 所有孩子都獲得相同的客戶 ID

[英]How do I implement a NamingContainer? All children get the same client ID

我嘗試編寫自己的樹組件。 樹節點呈現為包含樹組件的子組件的 div,例如:

<my:tree id="extendedTree"
         value="#{controller.rootNode}"
         var="node">
    <h:outputText id="xxx" value="#{node.name}" />
    <h:commandLink value="Test" actionListener="#{controller.nodeSelectionActionListener}" />
</my:tree>

到目前為止,一切都很好 - 一切都按預期工作,但h:outputText反復獲得相同的 id。
所以我讓我的組件實現javax.faces.NamingController ,覆蓋getContainerClientId()

@Override
public String getContainerClientId(FacesContext context) {
    String clientId = super.getClientId(context);
    String containerClientId = clientId + ":" + index;
    return containerClientId;
}

在節點迭代期間設置和更新index 但是getContainerClientId()只為每個孩子調用一次(不是像我期望的那樣為每個迭代和每個孩子調用)。 這會導致每個子 ID 都以相同的容器 ID 為前綴:

form:treeid:0:xxx

覆蓋getClientId()

我錯過了什么?

答案隱藏在JSF 1.2 規范第 3.1.6 章的底部:

3.1.6 客戶端標識符

...

除非調用setId() ,否則從該方法返回的值必須在組件實例的整個生命周期中相同,在這種情況下,它將在下一次調用getClientId()重新計算。

換句話說, getClientId()的結果默認由 JSF 組件緩存,如UIComponentBase#getClientId() (另請參見第 275 行的 nullcheck, 因為它在 Mojarra 1.2_15 中)並且當UIComponentBase#setId()重置此緩存時UIComponentBase#setId()被調用(另見第 358 行,因為它在 Mojarra 1.2_15 中)。 只要您不重置緩存的客戶端 ID,它就會在每次getClientId()調用時返回相同的值。

因此,在您的組件或渲染器的encodeChildren()實現中渲染子項時,最有可能看起來像這樣,

for (UIComponent child : getChildren()) {
    child.encodeAll(context);
}

你應該為每個孩子調用UIComponent#setId()UIComponent#getId()的結果在編碼孩子之前重置內部緩存的客戶端 ID:

for (UIComponent child : getChildren()) {
    child.setId(child.getId());
    child.encodeAll(context);
}

<h:dataTable>實現背后的UIData類也這樣做了(參見Mojarra 1.2_15 中的第 1382 行)。 請注意,這不是 JSF 1.x 特定的,這同樣適用於 JSF 2.x(以及 Facelets <ui:repeat>后面的UIRepeat類)。

值得一提的是,如果您的組件的子組件有子組件,那么也可能需要刷新它們的緩存 ID。 有了這個標記,稍微改編自原文:

<my:tree id="extendedTree"
         value="#{controller.rootNode}"
         var="node">
  <h:panelGroup layout="block" id="nodeBlock">
    <h:outputText id="xxx" value="#{node.name}" />
    <h:commandLink value="Test" actionListener="#{controller.nodeSelectionActionListener}" />
  </h:panelGroup>
</my:tree>

在應用上面的 BalusC 修復后, <panelGroup>的 id 出來了,但所有子組件在迭代器中都以 0 出來。

為了解決這個問題,也遍歷所有級別的子級並刷新它們的緩存 ID。 所以: child.setId(child.getId()); 變成uncacheId(child); 其中定義了uncacheId函數:

private void uncacheId(UIComponent el) {
    el.setId(el.getId());
    el.getChildren().forEach(this::uncacheId);
}

這可能很明顯,但我花了一段時間才弄明白,所以......

h:outputText id 為您提供與您沒有使其動態相同的信息。 您可以像這樣創建它:

 <h:outputText id="xxx_#{node.id}" value="#{node.name}" />

假設節點有一個唯一的“id”屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM