Frage

Hallo nochmal JSF Gurus.

Ich suche Hilfe bei benutzerdefinierten Renderern und Ajax-Handlern.Unser Projekt kann die normalen Optionsfeld- und Kontrollkästchen-Renderer nicht verwenden, da sie in Tabellen gerendert werden. Dies verstößt gegen unsere Unternehmensstandards.Wir können auch keine Komponentenbibliotheken von Drittanbietern verwenden.

Wir haben einen benutzerdefinierten Renderer, den wir jetzt in einigen Projekten verwendet haben und der einwandfrei funktioniert.Bei diesem speziellen Projekt muss ich jedoch den Ajax-Klick-Handler für einige Optionsfelder rendern.Befolgen Sie die Ratschläge in der Antwort auf diese Frage Ich habe den Anruf hinzugefügt zu RenderKitUtils.renderSelectOnclick(); und obwohl es anscheinend dasselbe JavaScript wie der Standardrenderer zu rendern scheint und das Firebug-Netzwerkfenster tatsächlich die ausgehende Anforderung anzeigt, wird mein Wertänderungs-Listener nicht ausgelöst und ich suche nach Hilfe, warum (es wird perfekt mit dem Standardrenderer ausgelöst)

Etwas Code:Erstens die Erstellung des Ajax-Handlers (das Optionsfeld wird programmgesteuert erstellt)

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

Mit dem Standardrenderer erzeugt dies:

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

und alles ist gut.Die Ajax-Anfrage wird gesendet und mein serverseitiger Listener wird ausgelöst.

Die relevanten Teile meines benutzerdefinierten Renderers:

 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
}

Update:Die Dekodierungsmethode in der Basisklasse für meinen Renderer lautet:

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

Dies rendert als :

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

Wie Sie sehen, ist der JavaScript-Klick-Handler identisch, ebenso wie die Attributwerte name und id der Eingabe-Tags.Obwohl dies die Ajax-Anforderung auslöst, wird der Listener nicht wie bei der ersten Version serverseitig ausgelöst.

Irgendwelche Ideen ?

War es hilfreich?

Lösung

Der decode() methode des Renderer (oder UIComponent wenn es keinen Renderer gibt) soll die Ajax-Anfrage basierend auf dekodieren javax.faces.behavior.event anforderungsparameter und Trigger ClientBehavior#decode() auf das passende Kundenverhalten.

Grundsätzlich ist die Logik wie folgt:

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

Angesichts der Tatsache, dass Sie verwenden RenderKitUtils und die generierte HTML-Ausgabe enthält mojarra.ab(), Ich gehe davon aus, dass Sie Mojarra verwenden.In diesem Fall ist es vielleicht klüger, Ihren benutzerdefinierten Renderer von zu erweitern RadioRenderer stattdessen, in dem all diese Logik bereits implementiert ist HtmlBasicRenderer und SelectManyCheckboxListRenderer damit Sie das Rad nicht neu erfinden müssen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top