Francisco, Sure... Can you send the jsf code and the html rendered on the client page?
-----Original Message----- From: Francisco Passos [mailto:[EMAIL PROTECTED] 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:[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: 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: [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]