p:inplace を使用して値が編集されたエンティティを取得するための次の強力な「ハック」を共有したいと思います。
私の質問は、 p:inplace またはその他の既存の属性を使用して、これをよりエレガントに実現する方法についてです。
このトリックは、Stackoverflow での BalusC の提案を基にしています。
JSF (および PrimeFaces) ManagedBean のメソッドにパラメーターを渡す方法
問題は、ap:inplace で編集された #{emp.firstName} を持つ Employee オブジェクトを取得することです。
<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>
BalusC からの提案は次のとおりです。
#{emp} が var 属性によって公開されている繰り返しコンポーネント内に実際にいると仮定すると、次のように値変更リスナー内の EL スコープから取得できます。
FacesContext context = FacesContext.getCurrentInstance();
Employee employee = context.getApplication().evaluateExpressionGet(context, "#{emp}", Employee.class);
Long id = employee.getId();
これに関する問題は、EL 式 (この場合は #{emp}) がハードコーディングされているため、再利用できないことです。
現在、p:inplace の ID を使用して、リスナー内のエンティティの EL 式として解析できる文字列を正常に伝播していますが、ドット '.' を使用できないためです。ID 文字列では、すべての「.」を翻訳する必要があります。ハイフン「-」としてこれをリスナーの有効なEL式に変換します。このようにして、非常に複雑な EL 式を伝播し、データベースにマージするエンティティ (または必要な永続化操作) を知ることができます。
public static String policy_convert_id_to_el_expression(String $id) {
if ($id == null) {
throw new IllegalArgumentException("null String $id");
}
return $id.replaceAll("-", ".");
}
BooleanValue、FloatQuantity などの特定の浅い値をラップする深い Value エンティティのファミリがあり、それぞれに具体的に型指定された getValue() メソッドと汎用の一時的な getObject() メソッドがあり、ラップされた浅い値に関する他の永続的なメタデータを保持しています。 (ユニット、作者など)。
次の ValueManager バッキング Bean があります。
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
..
}
これは非常に再利用可能な戦略になりました。
たとえば、List getFloors() を持つエンティティ OfficeBuilding があり、各 BuildingFloor には深い FloatQuantity getArea() エンティティがあり、FloatQuantity は Value を拡張します。
dataTable では、value=#{officeBuilding.floors} に対して var=floor を反復処理し、領域の浅い .value を代わりに編集します。
<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>
これは、高度に再利用可能で便利な複合コンポーネント resources/util/inplaceValue.xhtml としてカプセル化できます。
<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>
上記の例を使用すると、これは次のように呼び出されます。
<util:inplaceValue elid="floor-area" value=#{floor.area}/>
elid 属性を指定する際には注意が必要です。EL 式の "-" はハイフン "-" に変換されますが、さまざまな複雑なケースで魅力的に機能し、大量のコーディングを節約できます。それは非常にエレガントですが、それでもハックです。
Q: 値が編集されたエンティティーにアクセスするために必要な EL 式をリスナーに伝達するにはどうすればよいでしょうか?
また、特にこの目的のために、p:inplace の新しい属性についてPrimefaces 機能の提案を行いました。