我正在尝试使用复合组件在我的JSF 2项目中干掉弹出窗口。
此代码库使用Icefaces 3.3.0(由于历史原因,它们的1.8.2兼容层),Mojarra 2.2.7和Glassfish 4.1。
我有input.xhtml,它提供文本输入并使用2按钮弹出窗口(ok / cancel),然后基于弹出窗口构建。
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>
弹出窗口大部分按预期工作,即我可以输入内容,ok和cancel按钮工作,验证也可以。
什么行不通的是我的JavaScript代码在弹出窗口打开时尝试聚焦输入。
当我查看Firebug中的页面时,我发现输入的ID是MyForm:j_idt63:j_idt64:j_idt67:theInput
,但JavaScript代码会尝试使用ID为MyForm:j_idt63:theInput
的元素进行聚焦。
为什么#{cc.clientId}
中的input.xhtml
不是输入最终得到的正确ID?我需要做些什么来完成这项工作?
我已经看过BalusC's hint on adding a binding但我不想要绑定,因此复合组件可以独立于任何支持bean。
我在这里缺少什么吗?
答案 0 :(得分:2)
复合组件隐式naming containers。即他们将ID添加到孩子的客户ID中。这样就可以在同一个视图中使用多个,而不会让子代在生成的HTML输出中导致重复的ID。
在您的特定情况下,您将输入字段包装在另一个复合材料中,而另一个复合材料又包裹在另一个复合材料中。如果你绝对肯定你不需要在这个特定的组合中相互包装多个命名容器,那么那些(popup2buttons.xhtml
和popup.xhtml
)可能不应该是复合,而是<ui:decorate>
模板或<ui:composition>
标记文件。另请参阅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>
另一种方法是将它们重新加工成模板或标签文件。请注意,不要高估/过度使用复合材料。