【问题标题】:Accessing JSF nested composite component elements in JavaScript在 JavaScript 中访问 JSF 嵌套的复合组件元素
【发布时间】:2016-01-25 01:27:55
【问题描述】:

我正在尝试使用复合组件在我的 JSF 2 项目中干燥弹出窗口。

此代码库使用 Icefaces 3.3.0(出于历史原因,使用了 1.8.2 兼容层)、Mojarra 2.2.7 和 Glassfish 4.1。

我有 input.xhtml,它提供文本输入并使用 2 按钮弹出窗口(确定/取消),而后者又建立在基本弹出窗口之上。

input.xhtml:

<composite:interface>
    <!-- ... -->
    <composite:editableValueHolder name="forInput" targets="theInput"/>
</composite:interface>
<composite:implementation>
    <my:popup2Buttons>
        <ice:inputText id="theInput" value="..."/>
        <script>setInputFocus("#{cc.clientId}:theInput");</script>
    </my:popup2Buttons>
</composite:implementation>         

popup2buttons.xhtml:

<composite:interface>
    <!-- ... -->
</composite:interface>
<composite:implementation>
    <my:popup>
        <composite:insertChildren/>
        <ice:commandButton id="OkButton"
             value="Ok"
             actionListener="..."/>
        <ice:commandButton id="CancelButton"
              value="Cancel"
              actionListener="..."/>
    </my:popup>                    
</composite:implementation>

popup.xhtml:

<composite:interface>
    <!-- ... -->
</composite:interface>
<composite:implementation>
    <script>
    function setInputFocus(id) {
        document.getElementById(id).focus();
    }
    </script>

    <ice:panelPopup>
        <f:facet name="body">
            <h:panelGroup>
                <composite:insertChildren/>
            </h:panelGroup>
        </f:facet>
    </ice:panelPopup>
</composite:implementation>

弹出窗口大部分按预期工作,即我可以输入内容,确定和取消按钮工作,验证也工作。

不起作用的是我的 JavaScript 代码在弹出窗口打开时尝试聚焦输入。

当我在 Firebug 中查看页面时,我看到输入的 ID 是 MyForm:j_idt63:j_idt64:j_idt67:theInput,但 JavaScript 代码试图聚焦 ID 为 MyForm:j_idt63:theInput 的元素。

为什么input.xhtml 中的#{cc.clientId} 不是输入最终得到的正确ID?我需要做什么才能完成这项工作?

我见过BalusC's hint on adding a binding,但我不想要一个绑定,这样复合组件就可以独立于任何支持bean。

我还有什么遗漏的吗?

【问题讨论】:

    标签: jsf jsf-2 icefaces composite-component


    【解决方案1】:

    复合组件隐含naming containers。 IE。他们将他们的 ID 附加到孩子的客户 ID。这使得在同一个视图中使用多个它们成为可能,而它们的子级不会在生成的 HTML 输出中导致重复的 ID。

    在您的特定情况下,您将输入字段包装在另一个复合材料中,该复合材料又再次包装在另一个复合材料中。如果您绝对肯定不需要在此特定组合中相互包装多个命名容器,那么那些(popup2buttons.xhtmlpopup.xhtml)可能不应该是组合,而是&lt;ui:decorate&gt; 模板或@ 987654328@ 标记文件。另见When to use <ui:include>, tag files, composite components and/or custom components?

    回到技术问题,这是因为#{cc.clientId} 不是引用嵌套复合组件的ID,而是当前复合组件的ID。因此这将被关闭。至于binding 的潜在解决方案,您找到的答案并没有告诉您应该为此使用支持 bean。答案中的binding="#{foo}" 代码原样。它确实以这种方式工作,没有 bean 属性,另见JSF component binding without bean property。但是,当您在同一个视图中多次包含相同的复合材料并因此多个组件共享相同的binding="#{foo}" 时,此构造确实会失败。它确实不应该被多个组件共享,另见What is component binding in JSF? When it is preferred to be used?

    要在没有支持 bean 的情况下解决这个问题,您可以使用所谓的支持组件。

    com.example.InputComposite

    @FacesComponent("inputComposite")
    public class InputComposite extends UINamingContainer {
    
        private UIInput input;
    
        // +getter+setter.
    }
    

    input.xhtml

    <cc:interface componentType="inputComposite">
        ...
    </cc:interface>
    <cc:implementation>
        ...
        <h:inputText binding="#{cc.input}" ... />
        <script>setInputFocus("#{cc.input.clientId}");</script>
        ...
    </cc:implementation>
    

    另一种方法是将它们重新加工成模板或标记文件。请注意不要高估/过度使用复合材料。

    【讨论】:

    • 绑定方法似乎只适用于输入,但不适用于CommandButton。这是正确的还是我错过了什么?当我将 binding="#{okButton}" 属性添加到按钮时,它不会被渲染。这不是原始问题的一部分;我尝试在输入上有一个 onKeyPress 事件处理程序,并在用户按下 enter 时单击 ok 按钮,当用户按下 esc 时单击取消按钮。
    • 如果多个按钮组件共享相同的binding,可能会发生这种情况。您应该按照答案中的说明使用binding="#{cc.okButton}"
    猜你喜欢
    • 2011-09-14
    • 1970-01-01
    • 2012-11-18
    • 2014-03-07
    • 2012-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    相关资源
    最近更新 更多