强制jsf渲染自动生成的clientid

时间:2013-01-28 16:17:48

标签: jsf client-side clientid

我使用组件绑定和clientId属性来查找我的javascript代码中的组件,如下所示:

<div data-for="@parent" data-example="#{componentBindings.myInput.clientId}" />
...
<h:inputText binding="#{componentBindings.myInput}" value="#{myBean.myProperty}" />

唯一的问题是,jsf有时候不会渲染inputText字段的id属性,所以即使我知道js代码中的clientId,我也找不到该元素,因为它在客户端上没有id属性侧。

  1. 是否需要呈现自动生成的 ID标记?
  2. 有没有办法让jsf自动渲染所有cliendId-s? (如faces-config条目)
  3. 有没有办法确保呈现单个元素的clientId(没有明确地给它一个id)?
  4. 更新

    我找到了使用技巧的方法:

    <span id="#{componentBindings.myInput.clientId}">
        <h:inputText binding="#{componentBindings.myInput}" value="#{myBean.myProperty}" />
    </span>
    

    虽然在这种情况下有更好的方法,比如使用建议的名称,如果它不是你想用ajax渲染的输入字段,它可能是有用的。例如,使用facets:

    <!-- myComponent.xhtml -->
    <!-- ... -->
    <cc:interface>
        <cc:facet name="someFacet" required="true" />
    </cc:interface>
    <cc:implementation>
        <h:form>
            <cc:renderFacet name="someFacet"/>
        </h:form>
    </cc:implementation>
    
    <!-- page.xhtml -->
    <!-- ... -->
    <my:myComponent>
        <f:facet name="someFacet">
            <h:inputText />
            <!-- ... -->
        </f:facet>
    </my:myComponent>
    

    如果你看一下组件树,你会看到,facet没有嵌套在表单中,它是cc的直接子元素。所以用ajax执行cc会很好:

    <!-- myComponent.xhtml -->
    <!-- ... -->
    <cc:interface>
        <cc:facet name="someFacet" required="true" />
    </cc:interface>
    <cc:implementation>
        <h:form>
            <cc:renderFacet name="someFacet"/>
            <h:commandLink>
                <f:ajax execute=":#{cc.clientId}" render=":#{cc.clientId}" />
            </h:commandLink>
        </h:form>
    </cc:implementation>
    

    但这会抛出格式错误的xml异常,因为客户端没有请求id的元素。有了这个技巧,你可以使它工作:

    <cc:interface>
        <cc:facet name="someFacet" required="true" preferred="true"/>
    </cc:interface>
    
    <cc:implementation>
        <span id=#{cc.clientId}>
            <h:form>
                <cc:renderFacet name="someFacet"/>
                <h:commandLink>
                    <f:ajax execute=":#{cc.clientId}" render=":#{cc.clientId}" />
                </h:commandLink>
            </h:form>
        </span>
    </cc:implementation>
    

    我可能不是第一个发现这种解决方法的人,但我决定分享它,因为我没有找到它

1 个答案:

答案 0 :(得分:1)

来自Mojarra的HtmlBasicRenderer源代码(从2.1.17中的第672行开始):

/**
 * @param component the component of interest
 *
 * @return true if this renderer should render an id attribute.
 */
protected boolean shouldWriteIdAttribute(UIComponent component) {

    // By default we only write the id attribute if:
    //
    // - We have a non-auto-generated id, or...
    // - We have client behaviors.
    //
    // We assume that if client behaviors are present, they
    // may need access to the id (AjaxBehavior certainly does).

    String id;
    return (null != (id = component.getId()) &&
                (!id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX) ||
                    ((component instanceof ClientBehaviorHolder) &&
                      !((ClientBehaviorHolder)component).getClientBehaviors().isEmpty())));
}

因此,如果组件具有id属性集,或者组件具有客户端行为持有者(读取:id个孩子),它只会呈现HTML元素的<f:ajax>属性。

所以,你真的需要自己指定:

<h:inputText id="foo" ... />

否则,请更改您的JS代码,以便按name而不是id选择输入。