我想分享以下强大的“hack”,用于获取已使用 p:inplace 编辑其值的实体。
我的问题是如何使用 p:inplace 或其他现有属性更优雅地实现这一点。
该技巧改编自 BalusC 在 Stackoverflow 上的建议:
JSF(和 PrimeFaces)如何将参数传递给 ManagedBean 中的方法
那里的问题涉及获取具有 p: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 字符串中,我必须翻译每个“.”作为 hiphen '-',然后将其转换为侦听器中的有效 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 等,每个都有一个特定类型的 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 中,我使用 var=floor over value=#{officeBuilding.floors} 进行迭代,并就地编辑该区域的浅 .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 表达式中的内容被翻译为 hiphen“-”,
但它对于各种复杂的情况来说就像一个魅力,并且它节省了
大量的编码。它非常优雅,但仍然是一个 hack。
问:如何更好地将访问其值已被编辑的实体所需的 EL 表达式传播到侦听器?
我也有提出了 Primefaces 功能建议p:inplace 的新属性专门用于此目的。