Primefaces p: inplace: Como propagar com mais elegância a expressão EL para entidade mesclar

Eu gostaria de compartilhar o seguinte "hack" poderoso para chegar a uma entidade cujo valor foi editado usando p: inplace.

Minha pergunta é sobre como conseguir isso de forma mais elegante usando outros atributos existentes de p: inplace ou de outra forma.

O truque é adaptado de uma sugestão do BalusC no Stackoverflow:

JSF (e PrimeFaces) Como passar o parâmetro para um método no ManagedBean

A questão envolve a obtenção de um objeto Employee que tenha um p: inplace edited # {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>

A sugestão do BalusC é:

Supondo que você esteja de fato dentro de um componente repetitivo em que # {emp} tenha sido exposto pelo seu atributo var, você poderia simplesmente pegá-lo do escopo EL dentro do ouvinte de mudança de valor da seguinte forma:

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

O problema com isso é que a expressão EL (neste caso # {emp}) é codificada, portanto, isso não é reutilizável.

Agora estou usando o id do p: inplace com sucesso para propagar uma String que pode ser analisada como uma expressão EL para uma entidade dentro de um ouvinte, no entanto, já que não é possível usar um ponto '.' em um id String, eu tenho que traduzir cada '. como um hiphen '-' e então converta isso em uma expressão EL válida no listener. Dessa forma, posso propagar expressões EL muito complicadas e, em seguida, sei qual entidade mesclar ao banco de dados (ou qualquer operação de persistência necessária).

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

Eu tenho uma família de entidades profundas Value que envolvem valores superficiais específicos, como BooleanValue, FloatQuantity etc., cada um com um método getValue () especificamente digitado e um método getObject () transitório genérico e carregando outros metadados persistentes sobre o valor superficial envolvido (como unidades, autor etc.).

Eu tenho um bean backing ValueManager com:

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
..

}

Esta é agora uma estratégia altamente reutilizável.

Por exemplo, eu tenho uma entidade OfficeBuilding com List getFloors (), e cada BuildingFloor tem uma entidade de FloatQuantity getArea (), onde FloatQuantity estende Value.

Em uma dataTable, eu faço iteração com var = floor sobre value = # {officeBuilding.floors} e edito inplace o valor superficial da área assim:

<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>

Isso pode ser encapsulado como recursos de um componente composto altamente reutilizável e conveniente / util / inplaceValue.xhtml, portanto:

<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>

Usando o exemplo acima, isso é chamado de:

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

Basta lembrar de ter cuidado ao especificar o atributo elid que todas as ocorrências de "." na expressão EL são traduzidos para hiphen "-", mas funcionam como um encanto para uma ampla gama de casos complexos, e economizam uma enorme quantidade de codificação. É bem elegante, mas ainda é um hack.

P: Como alguém pode propagar melhor ao ouvinte a expressão EL necessária para acessar a entidade cujo valor foi editado?

eu também tenhofez uma sugestão de recurso Primefaces para um novo atributo para p: inplace especificamente para esse propósito.

questionAnswers(0)

yourAnswerToTheQuestion