Domanda

ciao di nuovo jsf guru.

Sto cercando aiuto su rendering personalizzati e gestori Ajax. Il nostro progetto non può utilizzare il normale pulsante di opzione e le caselle di controllo dei rendering mentre rendono nelle tabelle e questo è contro i nostri standard aziendali. Né possiamo usare librerie di componenti di terze parti.

Abbiamo un rendering personalizzato che abbiamo usato in alcuni progetti ora che funziona bene. Tuttavia, su questo particolare progetto, ho bisogno di rendering del gestore Ajax click per alcuni pulsanti radio. Seguendo il consiglio nella risposta a Questa domanda ho aggiunto la chiamata a RenderKitUtils.renderSelectOnclick(); E mentre sembra di rendere lo stesso JavaScript come il rendering standard, e in effetti, il pannello di rete Firebug mostra la richiesta in uscita, il mio listener di modifica del valore non viene sparato e sto cercando aiuto per il motivo per cui (si accende perfettamente con lo standard renderer)

Alcuni Codice: Innanzitutto, la creazione del gestore Ajax (il pulsante di opzione è creato programmaticamente)

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

wih il rendering standard, questo produce:

<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 tutto va bene. La richiesta Ajax è pubblicata e il mio ascoltatore lato server viene licenziato.

Le parti pertinenti del mio rendering personalizzato:

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

Aggiornamento: il metodo Decode nella classe base per il mio rendering è:

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

Questo rende come:

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

Come puoi vedere, JavaScript Fare clic con il gestore identico è identico, come lo sono i valori degli attributi Nome e ID dei tag di input. Sebbene questo innesca la richiesta Ajax, il listener non è il lato server alimentato come è con la prima versione.

Qualche idea?

È stato utile?

Soluzione

The decode() Metodo del Renderer (o UIComponent Se non c'è nessun rendering) dovrebbe decodificare la richiesta Ajax in base al parametro di richiesta javax.faces.behavior.event e al trigger ClientBehavior#decode() sui comportamenti del client corrispondente.

Fondamentalmente, la logica è la seguente:

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

Dato il fatto che stai usando RenderKitUtils e l'uscita HTML generata contiene mojarra.ab(), suppongo che tu stia usando Mojarra. In tal caso, è forse più saggio estendere il tuo rendering personalizzato da RadioRenderer invece che ha tutto questo logico già implementato in HtmlBasicRenderer e SelectManyCheckboxListRenderer in modo da non aver bisogno di reinventare la ruota.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top