如何创建动态JSF表单字段
我发现了一些类似的问题,比如一个,但是有很多方法可以做到这一点,这让我更加困惑 我们正在读取一个如何创建动态JSF表单字段,jsf,components,facelets,dynamic-forms,Jsf,Components,Facelets,Dynamic Forms,我发现了一些类似的问题,比如一个,但是有很多方法可以做到这一点,这让我更加困惑 我们正在读取一个XML文件。此XML包含一些需要显示的表单字段的信息 因此,我创建了这个定制的DynamicField.java,它包含了我们需要的所有信息: public class DynamicField { private String label; // label of the field private String fieldKey; // some key to identify the f
XML
文件。此XML
包含一些需要显示的表单字段的信息
因此,我创建了这个定制的DynamicField.java
,它包含了我们需要的所有信息:
public class DynamicField {
private String label; // label of the field
private String fieldKey; // some key to identify the field
private String fieldValue; // the value of field
private String type; // can be input,radio,selectbox etc
// Getters + setters.
}
所以我们有一个列表
我希望遍历此列表并填充表单字段,使其看起来像这样:
<h:dataTable value="#{dynamicFields}" var="field">
<my:someCustomComponent value="#{field}" />
</h:dataTable>
然后将返回相应的JSF表单组件(即标签、inputText)
另一种方法是只显示
,然后返回带有表单元素的HtmlDataTable
。(我认为这可能更容易做到)
哪种方法最好?有人能告诉我一些链接或代码,它显示了我如何创建这个?我更喜欢完整的代码示例,而不是回答“您需要一个子类
javax.faces.component.UIComponent
”如果源代码是XML,我建议采用完全不同的方法:。Facelets是基于XHTML的。您可以轻松地使用XSL从XML转换为XHTML。这是可以做到的,在JSF开始工作之前,有一点像样的过滤器
这里有一个启动示例
persons.xml
一
这个过滤器将使用persons.xsl
将persons.xml
转换为persons.xhtml
,最后将persons.xhtml
放在JSF期望的位置
诚然,XSL有一点学习曲线,但它是这项工作的正确工具,因为源是XML,目标也是基于XML的
要在表单和托管bean之间进行映射,只需使用Map
。如果您这样命名输入字段
...
提交的值将通过Map
键field1
、field2
、field3
等方式提供。因为源代码实际上不是XML,而是Javabean,而另一个答案不值得编辑成完全不同的风格(对于其他人将来的参考可能仍然有用),我将添加另一个基于Javabean来源的答案
当源代码是Javabean时,我基本上看到了三个选项
使用JSFrendered
属性或甚至JSTL
/
标记有条件地呈现或构建所需的组件。下面是使用渲染的属性的示例:
JSTL方法的一个例子可以在No中找到,JSTL绝对不是一个“坏习惯”。这个神话是JSF1.x时代遗留下来的,并且持续太久,因为初学者没有清楚地理解JSTL的生命周期和功能。在这一点上,只有当上述代码片段中的{bean.fields}
后面的模型至少在JSF视图范围内没有改变时,才能使用JSTL。另请参见,使用绑定
到bean属性仍然是一种“糟糕的做法”
至于
,您使用哪种迭代组件并不重要,您甚至可以像最初的问题一样使用
,或者使用特定于组件库的迭代组件,例如
或
至于收集提交的值,#{bean.values}
应该指向已经预创建的映射。一个HashMap
就足够了。如果控件可以设置多个值,则可能需要预填充贴图。然后,您应该使用列表
作为值预填充它。请注意,我希望字段#getType()
是枚举
,因为这样可以简化Java代码端的处理。然后可以使用switch
语句,而不是讨厌的if/else
块
在postAddToView
事件侦听器中以编程方式创建组件:
与:
(注意:不要自己创建HtmlForm
!使用JSF创建的表单,这个表单永远不会null
)
这保证了在正确的时刻填充树,并使getter不受业务逻辑的影响,并且避免了当{bean}
在比请求范围更广的范围内时出现潜在的“重复组件ID”问题(因此您可以在此处安全地使用视图范围的bean),并且保持bean没有UIComponent
属性,这反过来避免了组件作为可序列化bean的属性保存时可能出现的序列化问题和内存泄漏
如果您仍然在JSF 1.x上,
不可用,请通过绑定将表单组件绑定到请求(而不是会话!)范围的bean
然后懒洋洋地将其填充到表单的getter中:
public HtmlForm getForm() {
if (form == null) {
form = new HtmlForm();
// ... (continue with code as above)
}
return form;
}
当使用绑定时
,理解UI组件基本上是请求范围的,绝对不应该被分配为更大范围内bean的属性,这一点非常重要。另见
使用自定义渲染器创建自定义组件。我不打算发布完整的示例,因为这是一个非常紧密耦合的、特定于应用程序的混乱的大量代码
每种选择的利弊都应该清楚。它从最容易维护到最难维护,再从最不可重用到最可重用。由您选择最适合您的功能需求和当前情况的产品
应该注意的是,只有在Java中才有可能实现的东西是绝对的
public void populateForm(ComponentSystemEvent event) {
HtmlForm form = (HtmlForm) event.getComponent();
for (Field field : fields) {
switch (field.getType()) { // It's easiest if it's an enum.
case TEXT:
UIInput input = new HtmlInputText();
input.setId(field.getName()); // Must be unique!
input.setValueExpression("value", createValueExpression("#{bean.values['" + field.getName() + "']}", String.class));
form.getChildren().add(input);
break;
case SECRET:
UIInput input = new HtmlInputSecret();
// etc...
}
}
}
public HtmlForm getForm() {
if (form == null) {
form = new HtmlForm();
// ... (continue with code as above)
}
return form;
}