Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JSF事件不从具有支持组件的复合组件传播_Jsf_Composite Component - Fatal编程技术网

JSF事件不从具有支持组件的复合组件传播

JSF事件不从具有支持组件的复合组件传播,jsf,composite-component,Jsf,Composite Component,全部 我一直在为一个日期范围内的复合组件工作。基本上,我的复合组件使用下面的两个Richfaces 4.3日历组件来捕获各个日期值,生成一个日期范围(一对LocalDate对象)。我发现这是我的自定义组件的基础,该组件将日历上提交的两个值合并为一对值 一切似乎都很顺利,价值观也在不断更新。但是,我正在尝试找出如何将更改事件传播到使用xhtml页面以部分呈现另一个组件,但我没有成功。我已经尝试了我能想到的一切,但我想我错过了一些东西 页面: <rich:panel> <f

全部

我一直在为一个日期范围内的复合组件工作。基本上,我的复合组件使用下面的两个Richfaces 4.3日历组件来捕获各个日期值,生成一个日期范围(一对LocalDate对象)。我发现这是我的自定义组件的基础,该组件将日历上提交的两个值合并为一对值

一切似乎都很顺利,价值观也在不断更新。但是,我正在尝试找出如何将更改事件传播到使用xhtml页面以部分呈现另一个组件,但我没有成功。我已经尝试了我能想到的一切,但我想我错过了一些东西

页面:

<rich:panel>
    <f:facet name="header">Calendar Date Range Component</f:facet>
    <h:outputText id="out1" binding="#{calendarDateRangeTestBean.component1}"
                 value="#{calendarDateRangeTestBean.dateRange}" converter="localDatePairConverter" /><br/>
    <h:outputText id="out2" value="#{calendarDateRangeTestBean.dateRange}" converter="localDatePairConverter" /><b>NOT WORKING</b>
    <yxp:calendarDateRange id="calendarDateRange" value="#{calendarDateRangeTestBean.dateRange}"
        dataModel="#{calendarDateRangeTestBean}"
            valueChangeListener="#{calendarDateRangeTestBean.processValueChange}">
        <f:ajax execute="@all" listener="#{calendarDateRangeTestBean.processBehaviorEvent}"/>   

        <!-- This doesn't seem to work???? -->
        <f:ajax execute="@all" render="out2" />
    </yxp:calendarDateRange>
</rich:panel>

日历日期范围组件

不起作用
我的测试管理bean:

@ViewScoped
@ManagedBean
public class CalendarDateRangeTestBean extends AbstractCalendarDateRangeDataModel implements
        ValueChangeListener, Serializable {

   private static Logger logger = LoggerFactory.getLogger(CalendarDateRangeTestBean.class);

   private Pair<LocalDate> dateRange = Pair.of(LocalDate.now(), LocalDate.now().plusDays(7));

   private UIComponent component1;

   public UIComponent getComponent1() {
       return component1;
   }

   public LocalDateRange getDateRange() {
       return dateRange;
   }

   public void processBehaviorEvent(final javax.faces.event.AjaxBehaviorEvent event) {

       logger.info("processing event " + event + ": " + event.getBehavior());

       final FacesContext context = FacesContext.getCurrentInstance();
       logger.info("Setting render to " + component1.getClientId(context));

       // This seems to cause a rerender of the first component
       context.getPartialViewContext().getRenderIds().add(component1.getClientId(context));

   }

   @Override
   public void processValueChange(final ValueChangeEvent event) throws AbortProcessingException {
       logger.info(this.toString() + ": processing value change event " + event + ": ["
            + event.getOldValue() + ":" + event.getNewValue() + "]");
   }

   public void setComponent1(final UIComponent component1) {
       this.component1 = component1;
   }

   public void setDateRange(final Pair<LocalDate> dateRange) {
       logger.info("Setting date range to " + dateRange);
       this.dateRange = dateRange;
   }
@ViewScoped
@ManagedBean
公共类CalendarDateRangeTestBean扩展了AbstractCalendarDateRangeDataModel实现
ValueChangeListener,可序列化{
私有静态记录器Logger=LoggerFactory.getLogger(CalendarDateRangeTestBean.class);
private Pair dateRange=Pair.of(LocalDate.now(),LocalDate.now().plusDays(7));
专用UIComponent组件1;
公共UIComponent getComponent1(){
返回组件1;
}
公共LocalDateRange getDateRange(){
返回日期范围;
}
public void processBehaviorEvent(最终javax.faces.event.AjaxBehaviorEvent事件){
info(“处理事件”+event+:“+event.getBehavior());
final FacesContext context=FacesContext.getCurrentInstance();
info(“将渲染设置为”+component1.getClientId(上下文));
//这似乎会导致第一个组件的重新加载
context.getPartialViewContext().getRenderIds().add(component1.getClientId(context));
}
@凌驾
public void processValueChange(final ValueChangeEvent事件)引发AbortProcessingException{
logger.info(this.toString()+”:处理值更改事件“+事件+”:[“
+event.getOldValue()+“:“+event.getNewValue()+”]”;
}
公共无效集合组件1(最终UIComponent1){
this.component1=component1;
}
公共void setDateRange(最后一对日期范围){
logger.info(“将日期范围设置为“+日期范围”);
this.dateRange=日期范围;
}
}

我的复合组件:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:composite="http://java.sun.com/jsf/composite">

<!-- Methods exposed on rich:component are available in the __proto__ object. -->

<composite:interface componentType="com.yieldex.platform.ui.CalendarDateRange">
    <composite:attribute name="value" required="true" type="demo.Pair"/>
    <composite:attribute name="dataModel" required="false" type="demo.Pair" />
    <composite:clientBehavior name="change" event="change" targets="startCalendar endCalendar" default="true"/>
</composite:interface>

<composite:implementation>

    <h:outputStylesheet library="yieldex/platform" name="css/yieldex-platform.css" target="head" />

    <div id="#{cc.clientId}" class="yxp-calendar-date-range">
        <rich:calendar id="startCalendar" 
            binding="#{cc.startCalendar}"
            styleClass="yxp-start-date-range" 
            converter="localDateConverter" mode="ajax"
            dataModel="#{not empty cc.attrs.dataModel ? cc.attrs.dataModel.startCalendarDataModel : standardCalendarDateRangeDataModel.startCalendarDataModel}"
            monthLabels="#{dateRangeMessages.monthNames}"
            weekDayLabelsShort="#{dateRangeMessages.weeksShort}"
            monthLabelsShort="#{dateRangeMessages.monthNames}" popup="false"
            showInput="false" showFooter="false" showWeeksBar="false"
            showWeekDaysBar="true" showApplyButton="false"
            buttonIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}"
            buttonDisabledIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}">

            <f:facet name="weekDays"></f:facet>
            <f:ajax immediate="true" execute="@all" render="@this endCalendar"/>
        </rich:calendar>
        <rich:calendar id="endCalendar" 
            binding="#{cc.endCalendar}"
            styleClass="yxp-end-date-range" 
            converter="localDateConverter" mode="ajax"
            dataModel="#{not empty cc.attrs.dataModel ? cc.attrs.dataModel.endCalendarDataModel : standardCalendarDateRangeDataModel.endCalendarDataModel}"
            monthLabels="#{dateRangeMessages.monthNames}"
            weekDayLabelsShort="#{dateRangeMessages.weeksShort}"
            monthLabelsShort="#{dateRangeMessages.monthNames}" popup="false"
            showInput="false" showFooter="false" showWeeksBar="false"
            showWeekDaysBar="true" showApplyButton="false"
            buttonIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}"
            buttonDisabledIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}">

            <f:facet name="weekDays"></f:facet>
            <f:ajax immediate="true" execute="@all" render="startCalendar @this"/>
        </rich:calendar>
    </div>

</composite:implementation>
</ui:composition>
@FacesComponent("com.yieldex.platform.ui.CalendarDateRange")
public class YXCalendarDateRange extends UIInput implements NamingContainer {

    private UICalendar startCalendarComponent;
    private UICalendar endCalendarComponent;

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

        final Pair<LocalDate> value = (Pair<LocalDate>) this.getValue();
        if (value == null) {
            startCalendarComponent.setValue(null);
            endCalendarComponent.setValue(null);
        } else {
            startCalendarComponent.setValue(value.getStart());
            endCalendarComponent.setValue(value.getEnd());
        }

        super.encodeBegin(context);
    }

    @Override
    protected Object getConvertedValue(final FacesContext context, final Object submittedValue) {

        final LocalDate startDate = (LocalDate) startCalendarComponent.getConverter().getAsObject(context,
                startCalendarComponent, (String) this.startCalendarComponent.getSubmittedValue());

        final LocalDate endDate = (LocalDate) endCalendarComponent.getConverter().getAsObject(context,
                endCalendarComponent, (String) this.endCalendarComponent.getSubmittedValue());

       if (startDate == null || endDate == null) {
            return null;
       } else {

            if (startDate.isAfter(endDate)) {
                final FacesMessage message = new FacesMessage();
                message.setSeverity(FacesMessage.SEVERITY_ERROR);
                message.setSummary("start date cannot be after end date");
                message.setDetail("start date cannot be after end date");
                throw new ConverterException(message);
            }

            return Pair.of(startDate, endDate);
        }
    }

    public UICalendar getEndCalendar() {
        return this.endCalendarComponent;
    }

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

    public UICalendar getStartCalendar() {
        return this.startCalendarComponent;
    }

    @Override
    public Object getSubmittedValue() {
       return this;
    }

    public void setEndCalendar(final UICalendar endCalendarComponent) {
        this.endCalendarComponent = endCalendarComponent;
    }

    public void setStartCalendar(final UICalendar startCalendarComponent) {
        this.startCalendarComponent = startCalendarComponent;
    }
}

我的支持组件:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:composite="http://java.sun.com/jsf/composite">

<!-- Methods exposed on rich:component are available in the __proto__ object. -->

<composite:interface componentType="com.yieldex.platform.ui.CalendarDateRange">
    <composite:attribute name="value" required="true" type="demo.Pair"/>
    <composite:attribute name="dataModel" required="false" type="demo.Pair" />
    <composite:clientBehavior name="change" event="change" targets="startCalendar endCalendar" default="true"/>
</composite:interface>

<composite:implementation>

    <h:outputStylesheet library="yieldex/platform" name="css/yieldex-platform.css" target="head" />

    <div id="#{cc.clientId}" class="yxp-calendar-date-range">
        <rich:calendar id="startCalendar" 
            binding="#{cc.startCalendar}"
            styleClass="yxp-start-date-range" 
            converter="localDateConverter" mode="ajax"
            dataModel="#{not empty cc.attrs.dataModel ? cc.attrs.dataModel.startCalendarDataModel : standardCalendarDateRangeDataModel.startCalendarDataModel}"
            monthLabels="#{dateRangeMessages.monthNames}"
            weekDayLabelsShort="#{dateRangeMessages.weeksShort}"
            monthLabelsShort="#{dateRangeMessages.monthNames}" popup="false"
            showInput="false" showFooter="false" showWeeksBar="false"
            showWeekDaysBar="true" showApplyButton="false"
            buttonIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}"
            buttonDisabledIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}">

            <f:facet name="weekDays"></f:facet>
            <f:ajax immediate="true" execute="@all" render="@this endCalendar"/>
        </rich:calendar>
        <rich:calendar id="endCalendar" 
            binding="#{cc.endCalendar}"
            styleClass="yxp-end-date-range" 
            converter="localDateConverter" mode="ajax"
            dataModel="#{not empty cc.attrs.dataModel ? cc.attrs.dataModel.endCalendarDataModel : standardCalendarDateRangeDataModel.endCalendarDataModel}"
            monthLabels="#{dateRangeMessages.monthNames}"
            weekDayLabelsShort="#{dateRangeMessages.weeksShort}"
            monthLabelsShort="#{dateRangeMessages.monthNames}" popup="false"
            showInput="false" showFooter="false" showWeeksBar="false"
            showWeekDaysBar="true" showApplyButton="false"
            buttonIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}"
            buttonDisabledIcon="#{resource['yieldex/platform:img/1x1-transparent.png']}">

            <f:facet name="weekDays"></f:facet>
            <f:ajax immediate="true" execute="@all" render="startCalendar @this"/>
        </rich:calendar>
    </div>

</composite:implementation>
</ui:composition>
@FacesComponent("com.yieldex.platform.ui.CalendarDateRange")
public class YXCalendarDateRange extends UIInput implements NamingContainer {

    private UICalendar startCalendarComponent;
    private UICalendar endCalendarComponent;

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

        final Pair<LocalDate> value = (Pair<LocalDate>) this.getValue();
        if (value == null) {
            startCalendarComponent.setValue(null);
            endCalendarComponent.setValue(null);
        } else {
            startCalendarComponent.setValue(value.getStart());
            endCalendarComponent.setValue(value.getEnd());
        }

        super.encodeBegin(context);
    }

    @Override
    protected Object getConvertedValue(final FacesContext context, final Object submittedValue) {

        final LocalDate startDate = (LocalDate) startCalendarComponent.getConverter().getAsObject(context,
                startCalendarComponent, (String) this.startCalendarComponent.getSubmittedValue());

        final LocalDate endDate = (LocalDate) endCalendarComponent.getConverter().getAsObject(context,
                endCalendarComponent, (String) this.endCalendarComponent.getSubmittedValue());

       if (startDate == null || endDate == null) {
            return null;
       } else {

            if (startDate.isAfter(endDate)) {
                final FacesMessage message = new FacesMessage();
                message.setSeverity(FacesMessage.SEVERITY_ERROR);
                message.setSummary("start date cannot be after end date");
                message.setDetail("start date cannot be after end date");
                throw new ConverterException(message);
            }

            return Pair.of(startDate, endDate);
        }
    }

    public UICalendar getEndCalendar() {
        return this.endCalendarComponent;
    }

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

    public UICalendar getStartCalendar() {
        return this.startCalendarComponent;
    }

    @Override
    public Object getSubmittedValue() {
       return this;
    }

    public void setEndCalendar(final UICalendar endCalendarComponent) {
        this.endCalendarComponent = endCalendarComponent;
    }

    public void setStartCalendar(final UICalendar startCalendarComponent) {
        this.startCalendarComponent = startCalendarComponent;
    }
}
@FacesComponent(“com.yieldex.platform.ui.CalendarDateRange”)
公共类YXCalendarDateRange扩展UIInput实现NamingContainer{
专用UICalendar StartCalendar组件;
专用UICalendar EndCalendar组件;
@凌驾
public void encodeBegin(最终FacesContext上下文)引发IOException{
最终对值=(对)this.getValue();
如果(值==null){
startCalendarComponent.setValue(null);
endCalendarComponent.setValue(null);
}否则{
startCalendarComponent.setValue(value.getStart());
endCalendarComponent.setValue(value.getEnd());
}
super.encodeBegin(上下文);
}
@凌驾
受保护对象getConvertedValue(最终FacesContext上下文,最终对象submittedValue){
最终LocalDate startDate=(LocalDate)startCalendarComponent.getConverter().getAsObject(上下文,
startCalendarComponent,(字符串)this.startCalendarComponent.getSubmittedValue();
最终LocalDate endDate=(LocalDate)endCalendarComponent.getConverter().getAsObject(上下文,
endCalendarComponent,(字符串)this.endCalendarComponent.getSubmittedValue();
if(startDate==null | | endDate==null){
返回null;
}否则{
if(开始日期:isAfter(结束日期)){
最终FacesMessage消息=新FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_错误);
message.setSummary(“开始日期不能晚于结束日期”);
message.setDetail(“开始日期不能晚于结束日期”);
抛出新的ConverterException(消息);
}
返回对(开始日期、结束日期);
}
}
公共UICalendar getEndCalendar(){
返回此.endCalendar组件;
}
@凌驾
公共字符串getFamily(){
返回UINamingContainer.COMPONENT_族;
}
公共UICalendar getStartCalendar(){
返回此.startCalendarComponent;
}
@凌驾
公共对象getSubmittedValue(){
归还这个;
}
public void setEndCalendar(最终UICalendar endCalendar组件){
this.endCalendarComponent=endCalendarComponent;
}
公共作废设置开始日历(最终UICalendar开始日历组件){
this.startCalendarComponent=startCalendarComponent;
}
}
但我看到的是,价值观的改变正在到来。我还看到我的processBehaviorEvent被调用,并且在以编程方式调用时,第一个outputText被重新命名。但第二个似乎没有被重新招标。我试图弄清楚这是Mojarra 2.1.25中的一个bug,还是我的方法存在根本性的错误。如果您有任何建议,我们将不胜感激。

将根据所连接组件的父级对
中的任何客户端ID进行评估。在这个构造中,
最终被附加到复合组件中,复合组件本身就是一个命名容器。但是,组合中没有ID为
out2
的组件,这就是问题所在

要解决此问题,请指定绝对客户端ID。例如,当它位于
元素内时:

<f:ajax execute="@all" render=":formId:out2" />

如果是更合拍的话