Pergunta

Olá novamente Gurus do JSF.

Estou procurando ajuda sobre renderizadores personalizados e manipuladores de ajax.Nosso projeto não pode usar os renderizadores normais de botão de opção e caixa de seleção, pois eles são renderizados em tabelas e isso vai contra nossos padrões corporativos.Também não podemos usar bibliotecas de componentes de terceiros.

Temos um renderizador personalizado que usamos em alguns projetos que funciona bem.No entanto, neste projeto específico, preciso renderizar o manipulador de cliques ajax para alguns botões de opção.Seguindo o conselho na resposta a essa questão Eu adicionei a chamada para RenderKitUtils.renderSelectOnclick(); e embora pareça renderizar o mesmo javaScript que o renderizador padrão e, de fato, o painel de rede do firebug mostra a solicitação de saída, meu ouvinte de alteração de valor não está sendo acionado e estou procurando ajuda para saber o porquê (ele dispara perfeitamente bem com o padrão renderizador)

Algum código:Primeiramente, a criação do manipulador ajax (o botão de opção é criado programaticamente)

          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));

Com o renderizador padrão, isso produz:

<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>

e está tudo bem.A solicitação ajax é postada e meu ouvinte do servidor é acionado.

As partes relevantes do meu renderizador personalizado:

 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
}

Atualizar:O método de decodificação na classe base do meu renderizador é:

    @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);
}

Isso é renderizado como:

<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>

Como você pode ver, o manipulador de cliques javaScript é idêntico, assim como os valores dos atributos name e id das tags de entrada.Embora isso acione a solicitação Ajax, o ouvinte não é acionado no lado do servidor como acontece com a primeira versão.

Alguma ideia ?

Foi útil?

Solução

O decode() método do Renderer (ou UIComponent se não houver renderizador) deve decodificar a solicitação ajax com base em javax.faces.behavior.event parâmetro de solicitação e gatilho ClientBehavior#decode() nos comportamentos correspondentes do cliente.

Basicamente, a lógica é a seguinte:

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);
               }
           }
        }
    }
}

Dado o fato de que você está usando RenderKitUtils e a saída HTML gerada contém mojarra.ab(), presumo que você esteja usando Mojarra.Nesse caso, talvez seja mais sensato estender seu renderizador personalizado de RadioRenderer em vez disso, que tem toda essa lógica já implementada em HtmlBasicRenderer e SelectManyCheckboxListRenderer para que você não precise reinventar a roda.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top