- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在处理 JSF 自定义组件时遇到了一些困难。如果有人能让我先行一步,那就太好了。
这个想法是有一个组件可以让我翻阅 LocalDate
。考虑一个更简单的日期选择器。呈现的 HTML 有两个按钮,一个用于将日期增加一天,另一个按钮用于将日期减少一天。该值本身存储在隐藏的输入中。附件是该组件的一个简单版本,它不起作用,但希望描述了我想要实现的目标。
这个想法是说 <my:datePager value="#{myBackingBean.someDate}" />
在页面上,并在单击任一按钮后执行一些逻辑/操作。
例如<my:datePager value="#{myBackingBean.someDate} action="..." />
或<my:datePager value="#{myBackingBean.someDate} previous="..." next="..."/>
不知道哪个更好。
这就是我所遇到的问题:如何调用 previous
和next
组件上的方法?
这是迄今为止我的 JSF 2.3 自定义组件:
@FacesComponent(LocalDatePager.COMPONENT_TYPE)
public class LocalDatePager extends UIInput {
public static final String COMPONENT_TYPE = "LocalDatePager";
public LocalDatePager() {
setConverter(LocalDateConverter.INSTANCE);
}
public void previous() {
LocalDate localDate = (LocalDate) getValue();
localDate = localDate.minusDays(1);
setValue(localDate);
}
public void next() {
LocalDate localDate = (LocalDate) getValue();
localDate = localDate.plusDays(1);
setValue(localDate);
}
@Override
public void decode(FacesContext context) {
super.decode(context);
}
@Override
public void encodeEnd(FacesContext context) throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("div", this);
writer.writeAttribute("class", "btn-group", null);
writer.writeAttribute("role", "group", null);
writer.startElement("button", this);
writer.writeAttribute("type", "button", null);
writer.writeAttribute("class", "btn btn-outline-primary", null);
writer.writeText("Previous", null);
writer.endElement("button");
writer.startElement("button", this);
writer.writeAttribute("type", "button", null);
writer.writeAttribute("class", "btn btn-outline-primary", null);
writer.writeText("Next", null);
writer.endElement("button");
writer.endElement("div");
writer.startElement("input", this);
writer.writeAttribute("name", getClientId(context), "clientId");
writer.writeAttribute("type", "hidden", null);
writer.writeAttribute("value", getValue(), "value");
writer.endElement("input");
}
}
根据我的理解,我所拥有的组成部分是心灵,两者都是 UIInput
和UICommand
。我需要实现 ActionEvent
?火值变化事件?
目前,我在支持 bean 中而不是在组件中执行整个 previous 和 next 方法。这会导致大量重复代码,我认为自定义组件最适合。我尝试使用复合组件,但这也没有让我走得太远。
到目前为止,另一种方法是客户端行为:执行 JavaScript、更改隐藏输入的值并提交表单。这感觉更糟。
如果有人能给我指出正确的方向,那就太好了。
最佳答案
UIInput
首先,您需要在 encodeXxx()
方法中将按钮呈现为正常的提交按钮。另外,您宁愿使用 encodeAll()
而不是 encodeEnd()
来实现此目的,因为这似乎是一个“叶子”组件,因此您不希望来对付 child 。实现encodeAll() 会更加高效。将现有的 encodeEnd()
方法重命名为 encodeAll()
并调整按钮的编码,如下所示:
writer.startElement("button", this);
writer.writeAttribute("type", "submit", null); // instead of "button"
writer.writeAttribute("name", getClientId(context) + "_previous", "clientId");
writer.writeText("Previous", null);
// ...
writer.startElement("button", this);
writer.writeAttribute("type", "submit", null); // instead of "button"
writer.writeAttribute("name", getClientId(context) + "_next", "clientId");
writer.writeText("Next", null);
// ...
// The hidden input field in your existing code is fine as-is.
然后您可以在请求参数映射中检查它们。如果您想让您的组件保持为 UIInput
,那么我建议在 getConvertedValue()
方法中执行该工作:
@Override
protected Object getConvertedValue(FacesContext context, Object submittedValue) throws ConverterException {
LocalDate localDate = (LocalDate) super.getConvertedValue(context, submittedValue);
if (localDate != null) {
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
if (params.get(getClientId(context) + "_previous") != null) {
localDate = localDate.minusDays(1);
}
else if (params.get(getClientId(context) + "_next") != null) {
localDate = localDate.plusDays(1);
}
}
return localDate;
}
然后你可以简单地在值更改监听器中完成这项工作:
<my:datePager value="#{bean.localDate}" valueChangeListener="#{bean.onpage}" />
public void onpage(ValueChangeEvent event) {
// ...
}
这基本上就是全部了。无需手动触发值更改事件。其余逻辑已由 JSF 处理。
然而,这种方法的缺点是,这可能会在 JSF 生命周期的错误时刻被调用。当您确实希望在调用应用程序阶段调用它时,会在验证阶段调用值更改监听器。想象一下,这个按钮放置在一个表单中,其状态取决于与 #{bean.localDate}
关联的数据,那么它们的更新模型值阶段可能会出错,因为 localDate
code> 更改得太早了。
UICommand
如果上述缺点是真正的阻碍,尽管有 work around ,那么您最好将 UIInput
转换为 UICommand
。不可能两者兼而有之。你选择其中之一。我个人的建议是选择 UICommand,因为这对于 JSF 生命周期中的行为来说“更自然”,同时牢记组件的唯一目的(“分页到下一个/上一个日期”)。步骤如下:
将 extends UIInput
替换为 extends UICommand
。
删除构造函数中的 setConverter()
调用。
保留encodeAll()
方法。完全没问题。
删除 getConvertedValue()
方法并实现 decode()
,如下所示:
@Override
public void decode(FacesContext context) {
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
if (params.get(getClientId(context) + "_previous") != null) {
queueEvent(new ActionEvent(context, this));
}
else if (params.get(getClientId(context) + "_next") != null) {
queueEvent(new ActionEvent(context, this));
}
}
这些 queueEvent()
调用将导致调用同一组件的 broadcast()
。因此,按如下方式覆盖它:
@Override
public void broadcast(FacesEvent event) throws AbortProcessingException {
FacesContext context = event.getFacesContext();
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
LocalDate localDate = LocalDate.parse(params.get(getClientId())); // TODO: gracefully handle any conversion error.
if (params.get(getClientId(context) + "_previous") != null) {
localDate = localDate.minusDays(1);
}
else if (params.get(getClientId(context) + "_next") != null) {
localDate = localDate.plusDays(1);
}
getValueExpression("value").setValue(context.getELContext(), localDate);
super.broadcast(event); // Invokes bean method.
}
请注意value
属性是如何在模型中手动解码、转换和更新的。尽管这是作为隐藏输入值传递的,但您可能需要添加一些逻辑来妥善处理任何转换错误,如 TODO
中所示。
现在您可以按如下方式使用它:
<my:datePager value="#{bean.localDate}" action="#{bean.onpage}" />
public void onpage() {
// ...
}
关于jsf - 自定义组件,即 UIInput 和 UICommand,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64772479/
我正在尝试模拟 javax.faces.component.UIInput 类。 我的类(class)如下 public class MyBean{ private UIInput someI
这是问题所在,JSF 验证不断将字段翻转回最后一个已知值。 我们正在编辑一个支持 bean 已经有值的页面。 (频率=“每周”) 并且我们需要显示“请选择..”的默认值,即使该值不会通过验证(是的,我
在处理 JSF 自定义组件时遇到了一些困难。如果有人能让我先行一步,那就太好了。 这个想法是有一个组件可以让我翻阅 LocalDate 。考虑一个更简单的日期选择器。呈现的 HTML 有两个按钮,一个
在处理 JSF 自定义组件时遇到了一些困难。如果有人能让我先行一步,那就太好了。 这个想法是有一个组件可以让我翻阅 LocalDate 。考虑一个更简单的日期选择器。呈现的 HTML 有两个按钮,一个
我有一个可以操作合约的 Xpages 应用程序。一个过程使用“conService”字段中的契约(Contract)类型值来确定接下来必须发生的情况。下面的代码不会产生任何错误,但第三行似乎没有处理任
我正在尝试自定义 SystemEventListener为所有类型的实例注册 UIInput并对他们的 postValidate 使用react- 事件。根据我在网上找到的一个例子,我设法让一个运行
例如,在我使用带有参数的方法来获取我的 JSF 页面上组件的值之前 但是现在我需要相同的原则,但是在 inputText 元素的值属性上使用它,所以它或多或少像这样: 问题是当从 f:ajax 元
我想对getValue()之间的区别做一个说明性的解释。和 getLocalValue() UIInput components 的方法在执行多字段验证方面:jsf validate two fiel
我想在验证失败后将 JSF 输入重置为其原始托管 Bean 值。 我在同一页面中有两个表单 - 第一个表单有 commandLink初始化第二个表单。第二种表单呈现为一个对话框,其可见性通过 jQue
我正在使用 NGUI 的 UIInput 类来接受用户的文本输入。当我开始在移动设备中的文本框中输入内容时。出现一个键盘,它内部有另一个文本框,带有“确定”/“完成”按钮(就像键盘配件 View ,如
验证器类: @FacesValidator("br.gov.valec.sicpd.util.CpfValidator") public class CpfValidator implements V
TL;DR 即使 ajax 是立即执行的,单击也会导致验证。为什么? 我做不到终于解决了这个问题:
我正在尝试验证 ui:repeat 中的多个组件。 如何从 SiteBean 中的 ui:repeat 获取 UIInput? JSF 代码是:
更新:现在再次更新。我认为我之前的分析是错误的,因为我现在已经能够为此创建一个示例。它似乎与复合组件和 insertChildren 标签有关。 这是我的小脸:
我正在尝试编写一个渲染器来处理 placeholder 上的属性零件。阅读完JSF 2.0 strips out needed HTML5 attributes后,我走上了这条路这似乎是正确的。这是
jsf-api.jar 包含各种本地化的 Messages.properties 文件,这些文件一方面包含 javax.faces.component.UIInput.CONVERSION 键,另一方
我是一名优秀的程序员,十分优秀!