Details
-
Type: Improvement
-
Status: Closed
-
Priority: Major
-
Resolution: Fixed
-
Affects Version/s: 1.6
-
Component/s: ICE-Components
-
Labels:None
-
Environment:All
-
Support Case References:
Description
I'm proposing a little improvement for the MenuRenderer of ICEFaces, which it's
very important for our application.
We need using complex objects associated to a UISelectItem.
Usually, the value of an UISelectItem is a simple object (String, Integer,etc);
using a complex object is possible if there is a converter associated to the
UISelectOne component, which generates a "key" which identifies the complex
object in the getAsString() method of the Converter. In fact, in the generated
HTML page, the complex object has to be represented as a simple string in the
VALUE attribute of OPTION element.
But there's a problem during the rendering of the UISelectOne component, in fact
no option is selected, even if the model of the managed-bean is set to a value
which should match one of values contained in the list of the UISelectItems
component.
This happens when the current model and the matching element contained by the
UISelectItems component have the same "key", but they are two different
instances. The "key" is the string returned by the getAsString() method of the
associated Converter.
The class com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer is responsible
of writing the SELECTED attribute for the OPTION element which corresponds to
the model actually selected.
Looking at the
com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer.renderOption(FacesContext,
UIComponent, SelectItem, Element) method, when the submittedValue is not null,
the following code is executed:
Object selectedValues = getCurrentSelectedValues(uiComponent);
isSelected = isSelected(selectItem.getValue(), selectedValues);
The logic which determines if an option is selected does not use converted
values (it is not based on string comparison, but on generic Object comparison),
but the value obtained by the UIComponent is used.
I send you a patched version of the MenuRenderer class (version 1.5.3 of
ICEFaces, but the situation is identical in 1.6.0), which always uses the
converted value for calculating the selected item.
In fact, the formatComponentValue() method is called not only for the
submittedValue, but also for the value of SelectItem and UISelectOne: they are
treated in the same way.
If you don't like this solution and you prefer making comparison between the raw
value of components, I ask you if in the next releases it's possible to isolate
the code which contains the logic of determining the selected item, putting it
in a protected method; so I can easily change the logic in a sub-class of the
MenuRenderer.
For example, the
com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer.renderOption(FacesContext,
UIComponent, SelectItem, Element) method can be modified as in the following
code, adding the new isValueSelected method, which is protected, but your
original logic is completely unchanged:
protected void renderOption(FacesContext facesContext,
UIComponent uiComponent,
SelectItem selectItem, Element optionGroup)
throws IOException {
DOMContext domContext =
DOMContext.attachDOMContext(facesContext, uiComponent);
Element select = (Element) domContext.getRootNode();
Element option = domContext.createElement("option");
if (optionGroup == null) {
select.appendChild(option);
} else {
optionGroup.appendChild(option);
}
String valueString = formatComponentValue(facesContext, uiComponent,
selectItem.getValue());
option.setAttribute("value", valueString);
/* Now the logic is here!!!! */
boolean isSelected = isValueSelected(facesContext,selectItem,uiComponent);
if (isSelected) {
option.setAttribute("selected", "selected");
}
if (selectItem.isDisabled()) {
option.setAttribute("disabled", "disabled");
}
Document doc = domContext.getDocument();
Text labelNode = doc.createTextNode(selectItem.getLabel());
option.appendChild(labelNode);
}
protected boolean isValueSelected(FacesContext facesContext, SelectItem
selectItem,UIComponent uiComponent){
boolean isSelected;
String valueString = formatComponentValue(facesContext, uiComponent,
selectItem.getValue());
Object submittedValues[] =
getSubmittedSelectedValues(uiComponent);
if (submittedValues != null) {
isSelected = isSelected(valueString, submittedValues);
} else {
Object selectedValues =
getCurrentSelectedValues(uiComponent);
isSelected = isSelected(selectItem.getValue(), selectedValues);
}
return isSelected;
}
very important for our application.
We need using complex objects associated to a UISelectItem.
Usually, the value of an UISelectItem is a simple object (String, Integer,etc);
using a complex object is possible if there is a converter associated to the
UISelectOne component, which generates a "key" which identifies the complex
object in the getAsString() method of the Converter. In fact, in the generated
HTML page, the complex object has to be represented as a simple string in the
VALUE attribute of OPTION element.
But there's a problem during the rendering of the UISelectOne component, in fact
no option is selected, even if the model of the managed-bean is set to a value
which should match one of values contained in the list of the UISelectItems
component.
This happens when the current model and the matching element contained by the
UISelectItems component have the same "key", but they are two different
instances. The "key" is the string returned by the getAsString() method of the
associated Converter.
The class com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer is responsible
of writing the SELECTED attribute for the OPTION element which corresponds to
the model actually selected.
Looking at the
com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer.renderOption(FacesContext,
UIComponent, SelectItem, Element) method, when the submittedValue is not null,
the following code is executed:
Object selectedValues = getCurrentSelectedValues(uiComponent);
isSelected = isSelected(selectItem.getValue(), selectedValues);
The logic which determines if an option is selected does not use converted
values (it is not based on string comparison, but on generic Object comparison),
but the value obtained by the UIComponent is used.
I send you a patched version of the MenuRenderer class (version 1.5.3 of
ICEFaces, but the situation is identical in 1.6.0), which always uses the
converted value for calculating the selected item.
In fact, the formatComponentValue() method is called not only for the
submittedValue, but also for the value of SelectItem and UISelectOne: they are
treated in the same way.
If you don't like this solution and you prefer making comparison between the raw
value of components, I ask you if in the next releases it's possible to isolate
the code which contains the logic of determining the selected item, putting it
in a protected method; so I can easily change the logic in a sub-class of the
MenuRenderer.
For example, the
com.icesoft.faces.renderkit.dom_html_basic.MenuRenderer.renderOption(FacesContext,
UIComponent, SelectItem, Element) method can be modified as in the following
code, adding the new isValueSelected method, which is protected, but your
original logic is completely unchanged:
protected void renderOption(FacesContext facesContext,
UIComponent uiComponent,
SelectItem selectItem, Element optionGroup)
throws IOException {
DOMContext domContext =
DOMContext.attachDOMContext(facesContext, uiComponent);
Element select = (Element) domContext.getRootNode();
Element option = domContext.createElement("option");
if (optionGroup == null) {
select.appendChild(option);
} else {
optionGroup.appendChild(option);
}
String valueString = formatComponentValue(facesContext, uiComponent,
selectItem.getValue());
option.setAttribute("value", valueString);
/* Now the logic is here!!!! */
boolean isSelected = isValueSelected(facesContext,selectItem,uiComponent);
if (isSelected) {
option.setAttribute("selected", "selected");
}
if (selectItem.isDisabled()) {
option.setAttribute("disabled", "disabled");
}
Document doc = domContext.getDocument();
Text labelNode = doc.createTextNode(selectItem.getLabel());
option.appendChild(labelNode);
}
protected boolean isValueSelected(FacesContext facesContext, SelectItem
selectItem,UIComponent uiComponent){
boolean isSelected;
String valueString = formatComponentValue(facesContext, uiComponent,
selectItem.getValue());
Object submittedValues[] =
getSubmittedSelectedValues(uiComponent);
if (submittedValues != null) {
isSelected = isSelected(valueString, submittedValues);
} else {
Object selectedValues =
getCurrentSelectedValues(uiComponent);
isSelected = isSelected(selectItem.getValue(), selectedValues);
}
return isSelected;
}
Activity
- All
- Comments
- History
- Activity
- Remote Attachments
- Subversion