2014-12-30 4 views
5

У меня есть следующий код на моей странице facelet:Как передать атрибут из составного компонента в бэкэйн-бэк с помощью компонента backing?

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

Это мой составной компонент:

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

Как передать атрибуты from, to и text из составного компонента для резервного боб? Я имею в виду вводить эти значения в бэк-компонента, а не через

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

Update: есть более правильное определение того, что мне нужно: Уметь мутировать объекты, которые я прохожу от backing bean к composite component внутри backing component из composite component. Поэтому, когда я выполняю process или execute мой composite component Получаю обновленные значения.

Это моя поддержка компонента:

@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 
    */ 

} 

Я просто не могу понять, как я могу двигаться дальше? В общем, мне нужно принять значение от <p:inputText id="hiddenValue" value="#{cc.attrs.text}"/> и преобразовать его в два объекта Календари from и to. Будет здорово, если кто-нибудь может указать мне в правильном направлении отсюда. Я знаю, что мне нужно использовать getAttributes().put(key,value), но не знаю, где разместить этот код. Спасибо заранее.

+0

http://stackoverflow.com/questions/5460524/jsf-2-composite-component-passing-attributes-to-backing-bean Я думаю, что это поможет вам. ;) – xild

+0

Не совсем понятно, чего вы хотите достичь. Являются ли значения 'from' и' to' и являются 'text' выходным строковым представлением диапазона? –

+0

@ MicheleMariotti, no ** from ** и ** to ** должен быть в объектах «Календарь». Когда я изменяю ** Диапазон ** в ** составном компоненте **, он должен также изменить эти значения в бэкэнде. Текст предназначен только для тестирования. На самом деле я уже знаю, как это выполнить, но если я инкапсулирую 'from' и' to' в один объект и устанавливаю его через 'getSubmittedValue', но я сомневаюсь, что это можно сделать в двух объектах отдельно. – Anatoly

ответ

4

Основываясь на ваших комментариях, это то, что вы ожидаете.

Обратите внимание, что даже если эта реализация работает, это концептуально неверно!

Вы рассматриваете from и to в качестве входных сигналов (не входных компонентов, но входные значения) и text как OUTPUT. Это не так, как должен работать JSF!

Однако здесь

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

используется в странице:

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

с этой основы компонента:

@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; 
     } 
    } 
} 

с этим бэк-боба:

@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

Привет, это не совсем то, что мне нужно, я написал: Как передать атрибуты из и из композитного компонента в резервный компонент? ** Я имею в виду вставить эти значения в компонент backing **, а не через '', это полезно, когда мне нужно инкапсулировать некоторые бизнес-логики внутри компонента поддержки. – Anatoly

+0

Возможно, вы неправильно используете слово ** inject **, которое обычно связано с аннотациями, управляемыми контейнером, такими как '@ ManagedProperty',' @ Inject', '@ EJB', ... уточнять инъекцию и, возможно, я могу помочь :) –

+0

Возможно, вы правы. Я имел в виду мутировать объекты, которые я передаю из «поддерживающего компонента» в «составной компонент» внутри «вспомогательного компонента» «составного компонента». Возможно, это определение правильнее, я отредактирую свой пост. – Anatoly

4

я переписал код, используя BalusC tecnique (и без PrimeFaces):

вид:

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

композит:

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

подкладочный компонент:

@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; 
    } 
} 

и управляемый компонент:

@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; 
    } 
} 

Обратите внимание, что управляемый bean-компонент сохраняет только range property for get/set. From и to ушли, компонент поддержки получает и перестраивает их самостоятельно.