自定义渲染器不会触发ajax事件的侦听器

时间:2013-11-18 14:23:34

标签: ajax jsf jsf-2 broadcast custom-renderer

再次问好JSF大师。

我正在寻找有关自定义渲染器和ajax处理程序的帮助。我们的项目无法使用正常的单选按钮和复选框渲染器,因为它们在表格中呈现,这违反了我们的企业标准。我们也不能使用第三方组件库。

我们有一个自定义渲染器,我们现在已经在一些项目中使用了它可以正常工作。但是,在这个特定项目中,我需要为某些单选按钮呈现ajax单击处理程序。根据{{​​3}}答案中的建议,我已将调用添加到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
}

更新:我的渲染器的基类中的decode方法是:

    @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单击处理程序是相同的,输入标记的名称和id属性值也是相同的。虽然这会触发Ajax请求,但侦听器不会像第一个版本那样被激活服务器端。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

decode()Renderer方法(如果没有渲染器,则为UIComponent)应根据javax.faces.behavior.event请求参数解码ajax请求并触发{{3关于匹配的客户端行为。

基本上,逻辑如下:

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。在这种情况下,从ClientBehavior#decode()扩展您的自定义渲染器可能更明智,而RadioRendererHtmlBasicRenderer已经实现了所有这些逻辑,因此您无需重新发明轮子。