如何使用支持组件将属性从复合组件传递到辅助bean?

时间:2014-12-30 13:47:49

标签: jsf jsf-2 composite-component

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

如何将复合组件中的属性fromtotext传递给辅助bean?我的意思是在支持组件中注入这些值,而不是通过

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

更新:还有更正确的定义我需要什么:能够改变我从backing bean传递到composite component内的对象{ {1}}的{​​1}}。因此,当我执行backing componentcomposite 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,但不知道该代码的放置位置。提前感谢您。

2 个答案:

答案 0 :(得分:5)

根据您的意见,这是您所期望的。

请注意,即使此实施有效,在概念上也是错误的!

您正在考虑fromto作为INPUTS(不是输入组件,而是输入值)和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;
        }
    }
}

使用这个支持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
}

答案 1 :(得分: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;
    }
}

和托管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;
    }
}

请注意,托管bean仅为get / set保留range属性。 Fromto已消失,支持组件会自行派生并重建它们。