自定义渲染器不触发 ajax 事件的侦听器
-
26-12-2019 - |
题
再次向 JSF 大师们问好。
我正在寻找有关自定义渲染器和 ajax 处理程序的帮助。我们的项目无法使用普通的单选按钮和复选框渲染器,因为它们在表格中渲染,这违反了我们的公司标准。我们也不能使用第三方组件库。
我们有一个自定义渲染器,现在已经在一些项目中使用,效果很好。然而,在这个特定的项目中,我需要为一些单选按钮呈现 ajax 单击处理程序。按照答案中的建议进行操作 这个问题 我已将呼叫添加到 RenderKitUtils.renderSelectOnclick();
虽然它似乎渲染与标准渲染器相同的javaScript,并且事实上,firebug网络面板显示传出请求,但我的值更改侦听器没有被触发,我正在寻求帮助以了解为什么(它与标准渲染器完美地触发)渲染器)
一些代码:首先,创建ajax处理程序(单选按钮以编程方式创建)
AjaxBehavior valueChangeAction = (AjaxBehavior) FacesUtils.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
valueChangeAction.addAjaxBehaviorListener(new ProbeQuestionListener(currentQuestion, "probeDiv" + questionNumber,
probeDiv));
selectUI.addClientBehavior("valueChange", valueChangeAction);
valueChangeAction.setRender(Collections.singletonList("probeDiv" + questionNumber));
使用标准渲染器,会产生:
<table id="answer_1" class="marginLeft1a">
<tbody>
<tr>
<td>
<input id="answer_1:0" type="radio" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" value="0" name="answer_1">
<label for="answer_1:0"> Yes</label>
</td><td>
<input id="answer_1:1" type="radio" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" value="1" name="answer_1">
<label for="answer_1:1"> No</label>
</td>
</tr>
一切都很好。ajax 请求已发布,我的服务器端侦听器被触发。
我的自定义渲染器的相关部分:
public void encodeEnd(final FacesContext p_context, final UIComponent p_component) throws IOException {
/* set up convenience fields */
context = p_context;
component = p_component;
componentId = component.getClientId(context);
// rendering divs etc omitted.
while (iterator.hasNext()) {
final UIComponent childComponent = iterator.next();
// irrelevant code omited
if ("javax.faces.SelectItem".equals(childComponent.getFamily())) {
renderSelectItem(idIndex, childComponent);
idIndex++;
}
}
}
private void renderSelectItem(final int p_idIndex, final UIComponent p_childComponent) throws IOException {
// unrelated code omitted
writer.startElement("input", component);
writer.writeAttribute("type", getInputType(), null);
writer.writeAttribute("id", p_childComponentId, "id");
writer.writeAttribute("name", componentId, "clientId");
RenderKitUtils.renderSelectOnclick(context, component, false);
writer.endElement("input");
// unrelated code omitted
}
更新:我的渲染器基类中的解码方法是:
@Override
public void decode(final FacesContext p_context, final UIComponent p_component) {
final Map<String, String> valuesMap = p_context.getExternalContext().getRequestParameterMap();
final UIInput input = (UIInput) p_component; // NOSONAR
final Object value = valuesMap.get(input.getClientId(p_context));
// System.out.println("radio button decode: found " + value);
input.setSubmittedValue(value);
}
这呈现为:
<span class="marginLeft1a" id="answer_1">
<label for="answer_1:0">
<input type="radio" value="0" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" name="answer_1" id="answer_1:0">
Yes
</label>
<label for="answer_1:1">
<input type="radio" value="1" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" name="answer_1" id="answer_1:1">
No
</label>
</span>
正如您所看到的,javaScript 单击处理程序是相同的,输入标记的 name 和 id 属性值也是如此。尽管这会触发 Ajax 请求,但侦听器不会像第一个版本那样在服务器端触发。
有任何想法吗 ?
解决方案
这 decode()
的方法 Renderer
(或者 UIComponent
如果没有渲染器)应该根据以下内容解码ajax请求 javax.faces.behavior.event
请求参数及触发 ClientBehavior#decode()
匹配客户行为。
基本上逻辑如下:
Map<String, List<ClientBehavior>> behaviors = ((ClientBehaviorHolder) component).getClientBehaviors();
if (!behaviors.isEmpty()) {
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
String behaviorEvent = params.get("javax.faces.behavior.event");
if (behaviorEvent != null) {
List<ClientBehavior> behaviorsForEvent = behaviors.get(behaviorEvent);
if (behaviorsForEvent != null && !behaviorsForEvent.isEmpty()) {
String behaviorSource = params.get("javax.faces.source");
if (isBehaviorSource(context, behaviorSource, component.getClientId())) {
for (ClientBehavior behavior: behaviorsForEvent) {
behavior.decode(context, component);
}
}
}
}
}
鉴于您正在使用的事实 RenderKitUtils
生成的 HTML 输出包含 mojarra.ab()
, ,我假设您正在使用 Mojarra。在这种情况下,从以下位置扩展自定义渲染器可能是更明智的选择: RadioRenderer
相反,所有这些逻辑已经在 HtmlBasicRenderer
和 SelectManyCheckboxListRenderer
这样您就不需要重新发明轮子。