1

我想分享以下强大的“hack”,用于获取使用 p:inplace 编辑其值的实体。

我的问题是关于如何使用 p:inplace 或其他的其他现有属性更优雅地实现这一点。

该技巧改编自 BalusC 在 Stackoverflow 上的建议:

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 字符串中,我必须翻译每个“。” 作为一个 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>

这可以封装为高度可重用和方便的复合组件资源/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 表达式传播给侦听器?

我还专门为此目的为 p:inplace 的新属性提出了 Primefaces 功能建议。

4

0 回答 0