2014-12-30 31 views
5

Mam następujący kod w mojej strony facelet:Jak przekazać atrybut z komponentu kompozytowego do komponentu bean za pomocą komponentu zaplecza?

<hc:rangeChooser1 id="range_chooser" 
        from="#{testBean.from}" 
        to="#{testBean.to}" 
        listener="#{testBean.update}" 
        text="#{testBean.text}"> 
     <f:ajax event="rangeSelected" 
       execute="@this" 
       listener="#{testBean.update}"     
       render=":form:growl range_chooser"/> 
    </hc:rangeChooser1> 

To mój zespolonej:

<ui:component xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:cc="http://java.sun.com/jsf/composite" 
    xmlns:p="http://primefaces.org/ui"> 
    <cc:interface componentType="rangeChooser"> 
     <!-- Define component attributes here --> 
     <cc:clientBehavior name="rangeSelected" event="change" targets="hiddenValue"/> 
     <cc:attribute name="from" type="java.util.Calendar"/> 
     <cc:attribute name="to" type="java.util.Calendar"/> 
     <cc:attribute name="text" type="java.lang.String"/> 

    </cc:interface> 


    <cc:implementation> 

     <div id="#{cc.clientId}"> 
       ... 
       <p:inputText id="hiddenValue" value="#{cc.attrs.text}"/> 
       ... 
     </div> 
    </cc:implementation> 
</ui:component> 

Jak mogę przekazać atrybuty from, to i text ze składnika złożonego do tworzenia kopii Bean? Znaczy wstrzyknąć te wartości w składniku podłoża, a nie przez

<p:inputText id="hiddenValue" value="#{cc.attrs.text}"/> 

Aktualizacja: jest bardziej poprawna definicja, co jest potrzebne: Umieć mutować obiekty, które mijam z backing bean do composite component wewnątrz backing component z composite component. Więc kiedy wykonuję process lub execute my composite component otrzymuję zaktualizowane wartości.

To mój komponent podkład:

@FacesComponent("rangeChooser") 
public class RangeChooser extends UIInput implements NamingContainer { 
    private String text; 
    private Calendar from; 
    private Calendar to; 

    @Override 
    public void encodeBegin(FacesContext context) throws IOException{ 

     super.encodeBegin(context); 
    } 


    public String getText() { 
     String text = (String)getStateHelper().get(PropertyKeys.text); 
     return text; 
    } 

    public void setText(String text) { 
     getStateHelper().put(PropertyKeys.text, text); 
    } 

    /* 
     same getters and setters for Calendar objects, from and to 
    */ 

} 

po prostu nie mogę zrozumieć, jak mogę przejść? Generalnie muszę pobrać wartość z <p:inputText id="hiddenValue" value="#{cc.attrs.text}"/> i przekonwertować ją na dwa obiekty kalendarzy: from i to. Będzie świetnie, jeśli ktoś wskaże mi właściwy kierunek. Wiem, że muszę użyć getAttributes().put(key,value), ale nie wiem, gdzie umieścić ten kod. Z góry dziękuję.

+0

http://stackoverflow.com/questions/5460524/jsf-2-composite-component-passing-attributes-to-backing-bean Myślę, że to ci pomoże. ;) – xild

+0

Nie jest jasne, co chcesz osiągnąć. Czy są 'from' i' to' wejściami i jest 'tekstem' ciąg wyjściowy reprezentacja zakresu? –

+0

@MicheleMariotti, no ** from ** i ** to ** powinny być obiektami 'Calendar'. Kiedy zmienię ** Zakres ** w ** komponencie kompozytowym **, powinien on również zmienić te wartości w komponencie bean. Tekst służy wyłącznie do celów testowych. Właściwie już wiem, jak to zrobić, ale jeśli obuduję 'from' i' to' w jednym obiekcie i ustawię go za pomocą 'getSubmittedValue', ale wątpię, czy można to zrobić w dwóch obiektach oddzielnie. – Anatoly

Odpowiedz

4

Na podstawie twoich komentarzy jest to, czego oczekujesz.

Należy pamiętać, że nawet jeśli ta implementacja działa, jest to koncepcyjnie niepoprawna!

Państwo rozważają from i to jako wejścia (nie elementów wejściowych, ale wartości wejściowych) oraz text jako wyjście. To nie jest sposób, w jaki JSF ma działać!

Jednak tutaj jest

<cc:interface componentType="rangeComponent"> 
    <cc:attribute name="from" /> 
    <cc:attribute name="to" /> 
    <cc:clientBehavior name="rangeSelected" event="dateSelect" targets="from to"/> 
</cc:interface> 

<cc:implementation> 

    <div id="#{cc.clientId}"> 
     <p:calendar id="from" value="#{cc.attrs.from}"/> 
     <p:calendar id="to" value="#{cc.attrs.to}"/> 
    </div> 

</cc:implementation> 

stosowany w stronie:

<h:form> 
    <e:inputRange from="#{rangeBean.from}" to="#{rangeBean.to}" text="#{rangeBean.text}"> 
     <p:ajax event="rangeSelected" process="@namingcontainer" update="@form:output" listener="#{rangeBean.onChange}" /> 
    </e:inputRange> 

    <h:panelGrid id="output" columns="1"> 
     <h:outputText value="#{rangeBean.from}"/> 
     <h:outputText value="#{rangeBean.to}"/> 
     <h:outputText value="#{rangeBean.text}"/> 
    </h:panelGrid> 
</h:form> 

z tego składnika Podłoże:

@FacesComponent("rangeComponent") 
public class RangeComponent extends UINamingContainer 
{ 
    @Override 
    public void processUpdates(FacesContext context) 
    { 
     Objects.requireNonNull(context); 

     if(!isRendered()) 
     { 
      return; 
     } 

     super.processUpdates(context); 

     try 
     { 
      Date from = (Date) getValueExpression("from").getValue(context.getELContext()); 
      Date to = (Date) getValueExpression("to").getValue(context.getELContext()); 

      ValueExpression ve = getValueExpression("text"); 
      if(ve != null) 
      { 
       ve.setValue(context.getELContext(), from + " - " + to); 
      } 
     } 
     catch(RuntimeException e) 
     { 
      context.renderResponse(); 
      throw e; 
     } 
    } 
} 

z tego podkładu Fasola:

@ManagedBean 
@ViewScoped 
public class RangeBean implements Serializable 
{ 
    private static final long serialVersionUID = 1L; 

    private Date from = new Date(1000000000); 
    private Date to = new Date(2000000000); 
    private String text = "range not set"; 

    public void onChange(SelectEvent event) 
    { 
     Messages.addGlobalInfo("[{0}] changed: [{1}]", event.getComponent().getId(), event.getObject()); 
    } 

    // getters/setters 
} 
+0

Witam, to nie jest dokładnie to, czego potrzebuję, napisałem: Jak przekazać atrybuty z, do i tekst z komponentu kompozytowego do backing bean? ** Mam na myśli wstrzykiwanie tych wartości w składniku **, a nie przez '', jest to przydatne, gdy potrzebuję enkapsulować pewna logika biznesowa wewnątrz komponentu zaplecza. – Anatoly

+0

Prawdopodobnie niewłaściwie używasz słowa ** inject **, które jest zwykle związane z adnotacjami zarządzanymi przez kontener, takimi jak '@ ManagedProperty',' @ Inject', '@ EJB', ... wyjaśnienie wstrzyknięcia i może pomogę :) –

+0

Być może masz rację. Zamierzałem zmutować obiekty, które przechodzę od 'podkładu fasoli' do' komponentu kompozytowego' wewnątrz 'komponentu podkładu'' komponentu kompozytowego'. Być może ta definicja jest bardziej poprawna, będę edytować mój post. – Anatoly

4

I przepisał kod za BalusC tecnique (i bez PrimeFaces)

postać:

<h:form> 
    <e:inputRange value="#{rangeBean.range}"> 
     <p:ajax event="change" process="@namingcontainer" update="@form:output" 
      listener="#{rangeBean.onChange}" /> 
    </e:inputRange> 

    <h:panelGrid id="output" columns="1"> 
     <h:outputText value="#{rangeBean.range}" /> 
    </h:panelGrid> 
</h:form> 

kompozytu:

<cc:interface componentType="rangeComponent"> 
    <cc:attribute name="value" /> 
    <cc:clientBehavior name="change" event="change" targets="from to"/> 
</cc:interface> 

<cc:implementation> 

    <div id="#{cc.clientId}"> 
     <h:inputText id="from" binding="#{cc.from}"> 
      <f:convertDateTime type="date" pattern="dd/MM/yyyy" /> 
     </h:inputText> 
     <h:inputText id="to" binding="#{cc.to}"> 
      <f:convertDateTime type="date" pattern="dd/MM/yyyy" /> 
     </h:inputText> 
    </div> 

</cc:implementation> 

składnik Podłoże:

@FacesComponent("rangeComponent") 
public class RangeComponent extends UIInput implements NamingContainer 
{ 
    private UIInput from; 
    private UIInput to; 

    @Override 
    public String getFamily() 
    { 
     return UINamingContainer.COMPONENT_FAMILY; 
    } 

    @Override 
    public void encodeBegin(FacesContext context) throws IOException 
    { 
     String value = (String) getValue(); 
     if(value != null) 
     { 
      String fromString = StringUtils.substringBefore(value, "-"); 
      String toString = StringUtils.substringAfter(value, "-"); 

      try 
      { 
       from.setValue(from.getConverter().getAsObject(context, from, fromString)); 
      } 
      catch(Exception e) 
      { 
       from.setValue(new Date()); 
      } 

      try 
      { 
       to.setValue(to.getConverter().getAsObject(context, to, toString)); 
      } 
      catch(Exception e) 
      { 
       to.setValue(new Date()); 
      } 
     } 

     super.encodeBegin(context); 
    } 

    @Override 
    public Object getSubmittedValue() 
    { 
     return (from.isLocalValueSet() ? from.getValue() : from.getSubmittedValue()) + "-" + (to.isLocalValueSet() ? to.getValue() : to.getSubmittedValue()); 
    } 

    @Override 
    protected Object getConvertedValue(FacesContext context, Object submittedValue) 
    { 
     return from.getSubmittedValue() + "-" + to.getSubmittedValue(); 
    } 

    public UIInput getFrom() 
    { 
     return from; 
    } 

    public void setFrom(UIInput from) 
    { 
     this.from = from; 
    } 

    public UIInput getTo() 
    { 
     return to; 
    } 

    public void setTo(UIInput to) 
    { 
     this.to = to; 
    } 
} 

i zarządzany komponent bean:

@ManagedBean 
@ViewScoped 
public class RangeBean implements Serializable 
{ 
    private static final long serialVersionUID = 1L; 

    private String range = "01/01/2015-31/12/2015"; 

    public void onChange(AjaxBehaviorEvent event) 
    { 
     Messages.addGlobalInfo("[{0}] changed: [{1}]", event.getComponent().getId(), event.getBehavior()); 
    } 

    public String getRange() 
    { 
     return range; 
    } 

    public void setRange(String range) 
    { 
     this.range = range; 
    } 
} 

Należy pamiętać, że zarządzana fasola zachowuje tylko właściwość range dla get/set. From i to nie ma, składnik pomocniczy sam wywodzi i sam je odbudowuje.