Primefaces p: inplace: Jak bardziej elegancko propagować wyrażenie EL dla scalenia jednostki
Chciałbym udostępnić następujący potężny „hack”, aby dostać się do jednostki, której wartość została edytowana przy użyciu p: inplace.
Moje pytanie dotyczy tego, jak osiągnąć to bardziej elegancko, wykorzystując inne istniejące atrybuty p: w miejscu lub w inny sposób.
Ta sztuczka została zaadaptowana z sugestii BalusC na temat Stackoverflow:
JSF (i PrimeFaces) Jak przekazać parametr do metody w ManagedBean
Pytanie polega na uzyskaniu obiektu Employee, który ma edytowane p: inplace # {emp.firstName}:
<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>
Sugestia BalusC brzmi:
Zakładając, że rzeczywiście znajdujesz się w powtarzającym się komponencie, gdzie # {emp} został ujawniony przez jego atrybut var, możesz po prostu pobrać go z zakresu EL wewnątrz detektora zmiany wartości w następujący sposób:
FacesContext context = FacesContext.getCurrentInstance();
Employee employee = context.getApplication().evaluateExpressionGet(context, "#{emp}", Employee.class);
Long id = employee.getId();
Problem polega na tym, że wyrażenie EL (w tym przypadku # {emp}) jest zakodowane na stałe, więc nie jest to wielokrotne użycie.
Używam teraz identyfikatora p: umieszczam z powodzeniem w propagacji ciągu, który może być analizowany jako wyrażenie EL dla encji w słuchaczu, jednak ponieważ nie można użyć kropki „.” w id String muszę tłumaczyć co '.' jako hiphen '-', a następnie przekonwertuj to na poprawne wyrażenie EL w detektorze. W ten sposób mogę propagować bardzo skomplikowane wyrażenia EL, a następnie wiem, która jednostka ma zostać scalona z bazą danych (lub jakąkolwiek operacją trwałości jest wymagana).
public static String policy_convert_id_to_el_expression(String $id) {
if ($id == null) {
throw new IllegalArgumentException("null String $id");
}
return $id.replaceAll("-", ".");
}
Mam rodzinę jednostek o głębokiej wartości, które zawijają określone płytkie wartości, takie jak BooleanValue, FloatQuantity itp., Każda ze specjalnie wpisaną metodą getValue () i ogólną przejściową metodą getObject () oraz przenoszącą inne trwałe metadane o zawiniętej płytkiej wartości (takie jak jednostki, autor itp.).
Mam fasolę bazową ValueManager z:
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
..
}
To jest teraz strategia, która może być ponownie wykorzystana.
Na przykład, mam obiekt OfficeBuilding z List getFloors (), a każdy BuildingFloor ma deep FloatQuantity getArea (), gdzie FloatQuantity rozszerza wartość.
W dataTable I iteruj z var = floor ponad wartość = # {officeBuilding.floors} i edytuj w miejscu płytką wartość tego obszaru:
<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>
Może to być enkapsulowane jako wysoce nadające się do ponownego użycia i wygodne zasoby komponentu kompozytowego / util / inplaceValue.xhtml w ten sposób:
<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>
Używając powyższego przykładu, nazywa się to:
<util:inplaceValue elid="floor-area" value=#{floor.area}/>
Trzeba tylko pamiętać, aby zachować ostrożność przy określaniu atrybutu elid, który występuje we wszystkich wystąpieniach „.” w wyrażeniu EL są tłumaczone na hiphen „-”, ale działają jak urok dla szerokiej gamy złożonych przypadków i oszczędzają ogromne ilości kodowania. Jest dość elegancki, ale wciąż jest hackiem.
P: W jaki sposób można lepiej propagować do słuchacza wyrażenie EL potrzebne do uzyskania dostępu do obiektu, którego wartość została edytowana?
Ja teżzrobiłem propozycję funkcji Primefaces dla nowego atrybutu dla p: wstaw specjalnie dla tego celu.