Как передать атрибут из составного компонента в компонент поддержки с помощью компонента поддержки?
у меня есть следующий код на моей странице facelet:
<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
внутри a 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)
но не знаю, куда поместить этот код. заранее спасибо.
2 ответов
на основе ваших комментариев, это то, что вы ожидаете.
обратите внимание, что даже если эта реализация работает, это концептуально неверно!
вы рассматриваете from
и to
как входы (не входные компоненты, а входные значения) и text
как выход. Это не то, как 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;
}
}
}
С этой поддержкой bean:
@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
}
я переписал код с помощью 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;
}
}
обратите внимание, что управляемый компонент сохраняет только range
свойство для get / set. From
и to
ушли, компонент поддержки выводит и перестраивает их сам.