incubator-adffaces-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "William Hoover" <whoo...@nemours.org>
Subject RE: Keeping selectOneChoice selection
Date Mon, 09 Apr 2007 17:03:12 GMT
Francisco,

Sure... Can you send the jsf code and the html rendered on the client page?

-----Original Message-----
From: Francisco Passos [mailto:francisco.passos@opensoft.pt]
Sent: Monday, April 09, 2007 1:00 PM
To: adffaces-user@incubator.apache.org
Subject: RE: Keeping selectOneChoice selection


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:francisco.passos@opensoft.pt]
> 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:francisco.passos@opensoft.pt]
>> Sent: Monday, April 09, 2007 10:55 AM
>> To: adffaces-user@incubator.apache.org
>> 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:      francisco.passos@opensoft.pt
>
>
>


Francisco Passos
Opensoft - Soluções Informáticas, Lda
Telemóvel:  +351 91 238 52 76
Escritório: +351 21 380 44 10
Email:      francisco.passos@opensoft.pt



Mime
View raw message