Thank you for your hints.
I will bear this in mind when I come to this situation - which will be
soon enough.
However, back to this this particular scenario where no table is involved,
do you know of any way I manage to solve this problem?
> Francisco,
>
> I have found that there is a fundamental problem with how
> UINamingContainers are processed when row indexes are inserted into the
> ids of EditableValueHolders within the container rows.
>
> Understanding The Problem:
> As you may already know, tables have only columns referenced in the page
> so it can handle an almost infinite number of rows. Well, because you have
> only specified an id for a component within the table column the component
> inserts a row index reference in the holders id (via getClientRowKey() in
> a table) for each row. This ensures that each iteration of that row has a
> unique id. The problem with this is that in some cases this breaks
> automatic setting of bean values (if they are value bound to an
> EditableValueHolder within a row). Another issue is that "selectOneChoice"
> components in particular do not have a mechanism in place to ensure that a
> submitted value that gets set on the component is one of the values within
> the internal "SelectItemList" so virtually any value can get set on it. If
> the submitted value is not in the list it adds a blank entry in the drop
> down menu- what? I have also noticed that selectOneChoice component does
> not handle value conversion like regular input text components do.
> Semi-primitive values such as Integers, Booleans, etc. are not converted
> automatically like they are for regular input text components. I had some
> of the same issues with the "detailStamp" so I created an extended table
> component that allows only one toggled "detailStamp" at a time and
> overrides the "getClientRowKey()" excluding row indexes for components
> within the "detailStamp". This solution works very well, but still does
> not address EditableValueHolders within the rows themselves. It seems to
> me that we need to reevaluate the usage of inserting row indexes into ids!
>
> Possible Solutions:
> The first thing I would check is that you have the valuePassThru="true" to
> ensure that its not trying to use the index as the passed value (not sure
> why anyone would want to be restricted to just an index). If want to
> ensure that your value is never set to a value that does not exist in the
> options you can use a value change listener:
>
>
> /**
> * Verifies that an editable value holder event components value is a
> valid
> * option. If it is not it sets it back to the old value.
> *
> * @see #getEditableValueHolderValue(EditableValueHolder)
> * @param event
> */
> public final void verifyValueOption(ValueChangeEvent event) {
> try {
> if (event.getComponent() instanceof
> EditableValueHolder) {
> EditableValueHolder valueHolder =
> (EditableValueHolder) event
> .getComponent();
> if (!isValidSelectOption(event.getComponent(),
> event.getNewValue())) {
> // invalid option- regress to old value
>
> valueHolder.setValue(event.getOldValue());
>
> valueHolder.setSubmittedValue(event.getOldValue());
> }
> }
> } catch (Throwable e) {
> log.warn("Unable to verify select value. " +
> e.getMessage()
> + " cause: " + e.getCause());
> }
> }
>
> /**
> * Determines if the specified value is a valid selection option in the
> * specified select component.
> *
> * @param component
> * @param value
> * @return is the specified value a valid select option
> */
> public static final boolean isValidSelectOption(UIComponent component,
> Object value) {
> try {
> List<SelectItem> items =
> SelectItemSupport.getSelectItems(
> component,
> SelectItemSupport.getConverter(component));
> for (SelectItem item : items) {
> if (item.getValue() != null &&
> item.getValue().equals(value)) {
> return true;
> }
> }
> } catch (Exception e) {
> _LOG.warning("Unable to determine if the specified
> value: " + value
> + " is valid for the select component:
> " + component);
> }
> return false;
> }
>
>
>
> Probably not the most elegant solution, but nonetheless an effective one
> is to manage the submitted row index problems yourself. If nothing else
> this will provide you with a debugging tool to determine if the row index
> references are preventing your values from getting set:
> /**
> * <p>
> * Gets a parameter value from the request scope by an editale value
> holder
> * components id. This method will set/return the holders submitted
> value
> * from the request.
> * </p>
> * <p>
> * The holders client id is checked against a possible matching id
> request
> * parameter. The client id of the holder and the request parameter
> matching
> * the hodler id may have their own row indexing (such is the case with
> a
> * select menu).
> * <ol>
> * <li>The client id against the request parameter</li>
> * <li>The client id w/o row index against the request parameter</li>
> * <li>The client id against the request parameter w/o row index</li>
> * </ol>
> * </p>
> *
> * @param context
> * @param holder
> * @return the parameter value
> */
> @SuppressWarnings("unchecked")
> public static final Object getRequestParameterByHolderId(
> FacesContext context, EditableValueHolder holder) {
> if (log.isDebugEnabled())
> log.debug("getRequestParameterForNamingContainer(" +
> context + ','
> + holder + ")");
> if (holder != null && holder instanceof UIComponent) {
> String clientId = ((UIComponent)
> holder).getClientId(context);
> String clientIdWithOutRowIds =
> removeRowIdReferences(clientId);
> String id = ((UIComponent) holder).getId();
> Map<String, Object> map = context.getExternalContext()
> .getRequestParameterMap();
> if (map != null && map.entrySet() != null) {
> for (Map.Entry<String, Object> entry :
> map.entrySet()) {
> if (entry.getKey().indexOf(id) >= 0) {
> if
> (entry.getKey().equalsIgnoreCase(clientId)
> ||
> entry.getKey().equalsIgnoreCase(
>
> clientIdWithOutRowIds)
> ||
> removeRowIdReferences(
>
> entry.getKey()).equalsIgnoreCase(
>
> clientId)) {
> try {
>
> setConvertedAndValidatedValue(context,
>
> holder, entry.getValue());
> } catch (Exception e) {
>
> log.error("Unable to capture the converted "
>
> + "value for component(" + holder
>
> + ") value: " + entry.getValue(), e);
> }
> return
> holder.getSubmittedValue();
> }
> }
> }
> }
> }
> return null;
> }
>
> /**
> * Removes any row id references that may exist within the specified
> client
> * id
> *
> * @param clientId
> * @return the client id
> */
> public static final String removeRowIdReferences(String clientId) {
> if (log.isDebugEnabled())
> log.debug("removeRowIdReferences(" + clientId + ')');
> if (clientId != null) {
> String[] ids = clientId.split(String
>
> .valueOf(NamingContainer.SEPARATOR_CHAR));
> for (String id : ids) {
> try {
> Integer.parseInt(id);
> } catch (Exception e) {
> continue;
> }
> clientId =
> clientId.replace(NamingContainer.SEPARATOR_CHAR + id
> +
> NamingContainer.SEPARATOR_CHAR, String
>
> .valueOf(NamingContainer.SEPARATOR_CHAR));
> }
> }
> return clientId;
> }
>
> /**
> * Invokes the internal converter/validators(s) for an editable value
> holder
> * and returns the converted value
> *
> * @param context
> * @param holder
> * @param value
> * @return the converted value
> * @throws ValidatorException
> * @throws EvaluationException
> * @throws MethodNotFoundException
> */
> public static final Object setConvertedAndValidatedValue(FacesContext
> context,
> EditableValueHolder holder, Object value)
> throws ValidatorException, EvaluationException,
> MethodNotFoundException {
> if (holder != null) {
> if (holder.getConverter() != null) {
> value =
> holder.getConverter().getAsObject(context,
> (UIComponent) holder,
> value != null ?
> value.toString() : null);
> }
> if (holder instanceof UIComponent) {
> if (holder.getValidators() != null) {
> for (Validator v :
> holder.getValidators()) {
> v.validate(context,
> (UIComponent) holder, value);
> }
> }
> }
> if (holder.getValidator() != null) {
> holder.getValidator().invoke(context, new
> Object[] { value });
> }
> holder.setSubmittedValue(value);
> return value;
> }
> return null;
> }
>
> -----Original Message-----
> From: Francisco Passos [mailto:[EMAIL PROTECTED]
> Sent: Monday, April 09, 2007 11:17 AM
> To: William Hoover
> Subject: RE: Keeping selectOneChoice selection
>
>
> No, it is in a facet for a panelPage.
>
> In it, I have a panelGroupLayout, then a panelHorizontalLayout and finally
> in it the panelPage.
>
> If you feel it's best, I can attach the code or paste it in the mail body.
>
> Either way, if the selectOneChoice were in a table (something I will
> surely need), what would the solution be?
>
> Thank you,
>
> Francisco
>
>
>
>> Francisco,
>>
>> Is your selectOneChoice in a table?
>>
>> -----Original Message-----
>> From: Francisco Passos [mailto:[EMAIL PROTECTED]
>> Sent: Monday, April 09, 2007 10:55 AM
>> To: [email protected]
>> Subject: Keeping selectOneChoice selection
>>
>>
>> Hello there.
>>
>> I'm new to JSF and Trinidad, so please bear with my simplistic doubts.
>>
>> I'm struggling to keep a selectOneChoice selection upon a postback using
>> a
>> request-scoped bean.
>>
>> At first I couldn't even maintain the values in the list, but I found
>> that
>> placing a h:inputHidden on the page and declaring its value to be
>> #{myBean.valueList}, they could be kept. Furthermore I've tested the
>> seme
>> using pageFlow and it worked.
>>
>> However, I cannot keep the selected value in the dropdown list, it just
>> resets.
>>
>> What is the correct way to do this simple task without using session
>> beans?
>>
>> Thank you for your time and attention,
>>
>> Francisco Passos
>>
>>
>>
>
>
> Francisco Passos
> Opensoft - Soluções Informáticas, Lda
> Telemóvel: +351 91 238 52 76
> Escritório: +351 21 380 44 10
> Email: [EMAIL PROTECTED]
>
>
>
Francisco Passos
Opensoft - Soluções Informáticas, Lda
Telemóvel: +351 91 238 52 76
Escritório: +351 21 380 44 10
Email: [EMAIL PROTECTED]