Primefaces p: inplace: Wie Sie den EL-Ausdruck eleganter verbreiten, damit Entitäten zusammengeführt werden

Ich möchte den folgenden mächtigen "Hack" teilen, um an eine Entität heranzukommen, deren Wert mit p: inplace bearbeitet wurde.

Meine Frage ist, wie dies mit anderen vorhandenen Attributen von p: inplace oder auf andere Weise eleganter erreicht werden kann.

Der Trick basiert auf einem Vorschlag von BalusC zu Stackoverflow:

JSF (und PrimeFaces) Übergeben von Parametern an eine Methode in ManagedBean

Bei der dort gestellten Frage geht es darum, ein Employee-Objekt mit einem p: inplace zu finden, das mit # {emp.firstName} bearbeitet wurde:

<h:outputText value="First name:"/>
<p:inplace id="firstname" editor="true">
 <p:ajax event="save" onsuccess="#{employeeController.saveName()}"/>
 <p:inputText id="firstName" value="#{emp.firstName}"  
              required="true" label="text"
              valueChangeListener="#{employeeController.firstNameChanged}">
 <p:ajax event="valueChange" listener="#{employeeController.onValueChangedStart}"/>
 </p:inputText>
</p:inplace>

Der Vorschlag von BalusC ist:

Angenommen, Sie befinden sich tatsächlich in einer sich wiederholenden Komponente, in der # {emp} durch das var-Attribut verfügbar gemacht wurde, können Sie sie einfach wie folgt aus dem EL-Bereich im Listener für Wertänderungen abrufen:

FacesContext context = FacesContext.getCurrentInstance();
Employee employee = context.getApplication().evaluateExpressionGet(context, "#{emp}", Employee.class);
Long id = employee.getId();

Das Problem dabei ist, dass der EL-Ausdruck (in diesem Fall # {emp}) fest codiert ist und daher nicht wiederverwendbar ist.

Ich verwende jetzt die ID von p: inplace erfolgreich, um einen String zu verbreiten, der als EL-Ausdruck für eine Entität innerhalb eines Listeners analysiert werden kann, da jedoch kein Punkt 'verwendet werden kann.' In einer ID-Zeichenfolge muss ich jedes '.' als hiphen '-' und konvertieren Sie dies dann in einen gültigen EL-Ausdruck im Listener. Auf diese Weise kann ich sehr komplizierte EL-Ausdrücke weitergeben und weiß dann, welche Entität zur Datenbank zusammengeführt werden soll (oder welche Persistenzoperation erforderlich ist).

public static String policy_convert_id_to_el_expression(String $id) {
    if ($id == null) {
        throw new IllegalArgumentException("null String $id");
    }
    return $id.replaceAll("-", ".");
}

Ich habe eine Familie von Deep-Value-Entitäten, die bestimmte flache Werte wie BooleanValue, FloatQuantity usw. umschließen, jeweils mit einer spezifisch typisierten getValue () -Methode und einer generischen transienten getObject () -Methode und andere persistente Metadaten über den umschlossenen flachen Wert (wie Einheiten, Autor usw.).

Ich habe eine ValueManager Backing Bean mit:

public void onInplaceSaveEvent(AjaxBehaviorEvent ae) {
    UIComponent component = ae.getComponent();
    String id = component.getId();
    String $el = policy_convert_id_to_el_expression(id);
    FacesContext context = FacesContext.getCurrentInstance();
    Value v = context.getApplication().evaluateExpressionGet(context, "#{" + $el + "}", Value.class);
..
// merge Value entity to database (catches change to shallow wrapped value) 
// and/or perform other persistence operations such as metadata updates
..

}

Dies ist jetzt eine äußerst wiederverwendbare Strategie.

Zum Beispiel habe ich eine Entität OfficeBuilding mit List getFloors () und jede BuildingFloor hat eine tiefe Entität FloatQuantity getArea (), wobei FloatQuantity Value erweitert.

In einer Datentabelle iteriere ich mit var = floor over value = # {officeBuilding.floors} und bearbeite den flachen Wert der Fläche wie folgt:

<p:inplace 
 id="floor-area" 
 editor="true" 
 emptyLabel="UNDEF"
>
 <p:ajax 
  event="save" 
  update="@form" 
  listener="#{valueManager.onInplaceSaveEvent}"
  process="@this floor-area-value"
 />
 <p:inputText 
  id="floor-area-value" 
  value="#{floor.area.value}" 
 />
</p:inplace>

Dies kann als hochgradig wiederverwendbare und praktische Composite Component-Ressource / util / inplaceValue.xhtml eingekapselt werden.

<cc:interface>
  <cc:attribute name="value" type="com.example.entity.value.Value" required="true"/>
  <cc:attribute name="elid" required="true"/>
</cc:interface>

<cc:implementation>
    <p:inplace 
        id="#{cc.attrs.elid}" 
        editor="true" 
        emptyLabel="UNDEF"
        >
        <p:ajax 
            event="save" 
            update="@form" 
            listener="#{valueManager.onInplaceSaveEvent}"
            process="@this #{cc.attrs.elid}-value"
            />
        <p:inputText 
            id="#{cc.attrs.elid}-value" 
            value="#{cc.attrs.value.value}"                
            />
   </p:inplace>
</cc:implementation>

In dem obigen Beispiel heißt das:

<util:inplaceValue elid="floor-area" value=#{floor.area}/>

Man muss nur daran denken, vorsichtig zu sein, wenn man das elid-Attribut angibt, das alle Vorkommen von "." in der EL werden Ausdrücke in "-" übersetzt, aber es wirkt wie ein Zauber für eine Vielzahl komplexer Fälle und spart eine Menge Code. Es ist ziemlich elegant, aber es ist immer noch ein Hack.

F: Wie könnte man den EL-Ausdruck, der für den Zugriff auf die Entität benötigt wird, deren Wert bearbeitet wurde, besser an den Listener weitergeben?

Ich habe auchhat einen Vorschlag für ein Primefaces-Feature gemacht für ein neues Attribut für p: inplace speziell für diesen Zweck.

Antworten auf die Frage(0)

Ihre Antwort auf die Frage