The reason is that the HtmlSelectOneMenus that are used internally in the SelectInputDateRenderer are not getting the proper client id. They are rendering out:
id="popupDatePttrn1_sm"
instead of:
id="iceform:popupDatePttrn1_sm"
The missing portion is the id for the naming container. The reason turns out to be the order of operations for dynamically adding and removing the component itself. In SelectInputDateRenderer methods .writeMonthDropdown and writeYearDropdown, the items are added to the menu before the menu is added to the calendar:
HtmlSelectOneMenu dropDown = new HtmlSelectOneMenu();
dropDown.setId(component.getId() + SELECT_MONTH);
dropDown.setPartialSubmit(true);
dropDown.setTransient(true);
dropDown.setImmediate(component.isImmediate());
dropDown.setDisabled(component.isDisabled() || component.isReadonly());
dropDown.setStyleClass(component.getMonthYearDropdownClass());
UISelectItem selectItem;
Calendar calendar;
int currentMonth = timeKeeper.get(Calendar.MONTH);
for (int i = 0; i < months.length; i++) {
selectItem = new UISelectItem();
calendar = shiftMonth(facesContext, timeKeeper, currentDay, i - currentMonth);
selectItem.setItemValue(converter.getAsString(facesContext, component, calendar.getTime()));
selectItem.setItemLabel(months[i]);
dropDown.getChildren().add(selectItem);
if (i == currentMonth)
{
dropDown.setValue(selectItem.getItemValue());
}
}
//The menu is added as a child of the calendar after the menu items are set. This works in Mojarra but not MyFaces
component.getChildren().add(dropDown);
dropDown.encodeBegin(facesContext);
dropDown.encodeChildren(facesContext);
dropDown.encodeEnd(facesContext);
component.getChildren().remove(dropDown);
MyFaces doesn't like this because adding the menu to the calendar has the side effect of setting the parent and allowing the client id to be calculated. To appease both MyFaces and Mojarra, we just have to move the logic adding the menu to the calendar before we start setting the actual menu items:
HtmlSelectOneMenu dropDown = new HtmlSelectOneMenu();
dropDown.setId(component.getId() + SELECT_MONTH);
dropDown.setPartialSubmit(true);
dropDown.setTransient(true);
dropDown.setImmediate(component.isImmediate());
dropDown.setDisabled(component.isDisabled() || component.isReadonly());
dropDown.setStyleClass(component.getMonthYearDropdownClass());
//Add the menu to the calendar's children before adding any menu items.
component.getChildren().add(dropDown);
UISelectItem selectItem;
Calendar calendar;
int currentMonth = timeKeeper.get(Calendar.MONTH);
for (int i = 0; i < months.length; i++) {
selectItem = new UISelectItem();
calendar = shiftMonth(facesContext, timeKeeper, currentDay, i - currentMonth);
selectItem.setItemValue(converter.getAsString(facesContext, component, calendar.getTime()));
selectItem.setItemLabel(months
[i]);
dropDown.getChildren().add(selectItem);
if (i == currentMonth) {
dropDown.setValue(selectItem.getItemValue());
}
}
dropDown.encodeBegin(facesContext);
dropDown.encodeChildren(facesContext);
dropDown.encodeEnd(facesContext);
component.getChildren().remove(dropDown);
The reason is that the HtmlSelectOneMenus that are used internally in the SelectInputDateRenderer are not getting the proper client id. They are rendering out:
id="popupDatePttrn1_sm"
instead of:
id="iceform:popupDatePttrn1_sm"
The missing portion is the id for the naming container. The reason turns out to be the order of operations for dynamically adding and removing the component itself. In SelectInputDateRenderer methods .writeMonthDropdown and writeYearDropdown, the items are added to the menu before the menu is added to the calendar:
HtmlSelectOneMenu dropDown = new HtmlSelectOneMenu();
dropDown.setId(component.getId() + SELECT_MONTH);
dropDown.setPartialSubmit(true);
dropDown.setTransient(true);
dropDown.setImmediate(component.isImmediate());
dropDown.setDisabled(component.isDisabled() || component.isReadonly());
dropDown.setStyleClass(component.getMonthYearDropdownClass());
UISelectItem selectItem;
{ dropDown.setValue(selectItem.getItemValue()); }Calendar calendar;
int currentMonth = timeKeeper.get(Calendar.MONTH);
for (int i = 0; i < months.length; i++) {
selectItem = new UISelectItem();
calendar = shiftMonth(facesContext, timeKeeper, currentDay, i - currentMonth);
selectItem.setItemValue(converter.getAsString(facesContext, component, calendar.getTime()));
selectItem.setItemLabel(months[i]);
dropDown.getChildren().add(selectItem);
if (i == currentMonth)
}
//The menu is added as a child of the calendar after the menu items are set. This works in Mojarra but not MyFaces
component.getChildren().add(dropDown);
dropDown.encodeBegin(facesContext);
dropDown.encodeChildren(facesContext);
dropDown.encodeEnd(facesContext);
component.getChildren().remove(dropDown);
MyFaces doesn't like this because adding the menu to the calendar has the side effect of setting the parent and allowing the client id to be calculated. To appease both MyFaces and Mojarra, we just have to move the logic adding the menu to the calendar before we start setting the actual menu items:
HtmlSelectOneMenu dropDown = new HtmlSelectOneMenu();
dropDown.setId(component.getId() + SELECT_MONTH);
dropDown.setPartialSubmit(true);
dropDown.setTransient(true);
dropDown.setImmediate(component.isImmediate());
dropDown.setDisabled(component.isDisabled() || component.isReadonly());
dropDown.setStyleClass(component.getMonthYearDropdownClass());
//Add the menu to the calendar's children before adding any menu items.
component.getChildren().add(dropDown);
UISelectItem selectItem;
Calendar calendar;
int currentMonth = timeKeeper.get(Calendar.MONTH);
for (int i = 0; i < months.length; i++) {
selectItem = new UISelectItem();
calendar = shiftMonth(facesContext, timeKeeper, currentDay, i - currentMonth);
selectItem.setItemValue(converter.getAsString(facesContext, component, calendar.getTime()));
selectItem.setItemLabel(months[i]);
dropDown.getChildren().add(selectItem);
if (i == currentMonth) { dropDown.setValue(selectItem.getItemValue()); }
}
dropDown.encodeBegin(facesContext);
dropDown.encodeChildren(facesContext);
dropDown.encodeEnd(facesContext);
component.getChildren().remove(dropDown);