-
1. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
igor_d Aug 5, 2008 3:16 AM (in response to igor_d)I meant:
input.getClientId(facesContext)
In ver. 3.1.* returns:
reportForm:customers:0:fullName
In ver. 3.2.* returns:
reportForm:customers:fullName -
2. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
ilya_shaikovsky Aug 5, 2008 3:46 AM (in response to igor_d)already found this and fixed in latest 3.2.2 snapshots.
-
3. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
igor_d Sep 8, 2008 11:00 PM (in response to igor_d)Hi Ilya,
We have tested the issues with 3.2.2.CR4.
Below is my explanation:
If you have in a form:<a4j:repeat id="customers" value="#{customers}" var="party"> <rich:panel id="customerDetailsPanel" header="PART A> <h:inputText id="fullName" required="true" requiredMessage="party.mainName.isNull" value="#{party.nameMainNameText}"/>
We have a PhaseListener, which adds to the input component our Validator, which validates the input.
The issues are:
1) inputComponent.getSubmittedValue() still returns null, which is different to 3.1.* (this is not fixed yet)
2) in our validator in the standard interface method
public void validate(final FacesContext facesContext, final UIComponent component, final Object value) throws ValidatorException {
if value is invalid we add message:facesContext.addMessage(input.getClientId(facesContext), facesMessage)
In that placeinput.getClientId(facesContext)
returns the correct value:
reportForm:customers:0:fullName
(this is fixed, thanks!)
2) In another place (PhaseListener:
public void afterPhase(final PhaseEvent e) {
we call input.getClientId(facesContext), and that returns:
reportForm:customers:fullName
And that is different to 3.1.* (this is not fixed yet)
3) Later on we want to see which panel this input control belongs to. We call panelComponent.getClientId(context).
That also returns incorrect value:
reportForm:customers:customerDetailsPanel
not what we expect:
reportForm:customers:0:customerDetailsPanel
this is not fixed, too
Can you please have another look. It looks like the getClientId(facesContext) problem is fixed in one place, but it's not in some other places.
Best regards,
Igor -
4. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
nbelaevski Sep 9, 2008 6:53 AM (in response to igor_d)"igor_d" wrote:
2) In another place (PhaseListener:
public void afterPhase(final PhaseEvent e) {
we call input.getClientId(facesContext), and that returns:
reportForm:customers:fullName
And that is different to 3.1.* (this is not fixed yet)
3) Later on we want to see which panel this input control belongs to. We call panelComponent.getClientId(context).
That also returns incorrect value:
reportForm:customers:customerDetailsPanel
not what we expect:
reportForm:customers:0:customerDetailsPanel
this is not fixed, too
Can you please have another look. It looks like the getClientId(facesContext) problem is fixed in one place, but it's not in some other places.
Best regards,
Igor
Igor,
It is ok that there is no row index is appended to client id when client id is calculated inside phase listener. Probably 3.1.x contains a bug that causes wrong calculation of client id. -
5. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
igor_d Sep 9, 2008 7:34 PM (in response to igor_d)Hi Nick,
well, I don't think it's ok, because if we have several iterations of customers, then how can we define which one which, if client id is the same for all.
Also, we don't use (see problem #3) panel.getClientId() in PhaseListener, but in a controller to render invalid messages with link to their input controls, which are located in particular panels (so, we use java script onclick: 1. make all panels hidden, 2. make the panel with invalid value visible, 3. go to the invalid input control).
We have several panels with only 1 visible, which is selected by a user. So we need to know the client id of the panel to make it visible.
Another thing is, why would it be correct in Validator.validate method but not everywhere else. Should not we make it consistent?
Thanks again,
Igor -
6. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
nbelaevski Sep 10, 2008 7:17 AM (in response to igor_d)Igor,
Client id is built dynamically for components inside iterables like dataTable, repeat, etc. It contains current row identifier when:
1. In the context of iterable component being processed (e.g. decoded, validated, encoded etc.)
2. When events queued from component inside iterable component are broadcast (e.g. command link inside data table)
3. In the context of invokeOnComponent() method
Can you provide full page code or little test case application to find out what's really going on? -
7. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
igor_d Sep 12, 2008 4:41 AM (in response to igor_d)Hi Nick,
here is a method, which we use to define if the value was entered into the "required" field:public void afterPhase(final PhaseEvent e) { final FacesContext fc = FacesContext.getCurrentInstance(); final List<UIInput> components = new ArrayList<UIInput>(); JSFUtil.getUIComponentsByType(fc, UIInput.class, components); for (final UIInput inputComponent : components) { // if input was required, check if submitted value is not empty if (Boolean.TRUE.equals(inputComponent.getAttributes().get(INPUT_REQUIRED))) { OurJsfValidator.validateRequired(fc, inputComponent); } } }
What we want to achive is to be able to submit form with invalid data (save "dirty data" into xml field), so a user can work on them later.
For that we used attribute inputRequired:
<h:inputText value="#{controller.someVar}" inputRequired="true"/>
That will not break the standard JSF validation with required="true". But we still want to check the value.
Here is the static method in OurJsfValidator:public static void validateRequired(final FacesContext facesContext, final UIInput input) { if (Boolean.TRUE.equals(input.getAttributes().get(EMPTY_VALUE))) { String message = input.getRequiredMessage(); if (!StringUtils.isEmpty(message)) { message = message.indexOf("{") == 0 && message.indexOf("}") == message.length() - 1 ? SeamResourceBundle .getBundle().getString(message.substring(1, message.length() - 1)) : message; } else { message = MESSAGE_INPUT_REQUIRED; } facesContext.addMessage(input.getClientId(facesContext), FacesMessages.createFacesMessage( FacesMessage.SEVERITY_ERROR, message)); } }
As you can see we want to create a faces message and assign it to the correct input field. But since the client id is not calculated correctly we have incorrect links for the validation messages.
The attribute EMPTY_VALUE is set to 'true' before validation, and in validation we set it to 'false' if there was some value. But if there is no value JSF does not call our validator, so we have to use this attribute.
So, this is the problem, which appears to be in ver 3.2.2.GA. That all works fine in 3.1.*
Thanks,
Igor -
8. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
igor_d Sep 16, 2008 2:04 AM (in response to igor_d)From http://java.sun.com/javaee/5/docs/api/:
public abstract String getClientId(FacesContext context)Return a client-side identifier for this component, generating one if necessary. The associated Renderer, if any, will be asked to convert the clientId to a form suitable for transmission to the client.
The return from this method must be the same value throughout the lifetime of the instance, unless the id property of the component is changed, or the component is placed in a NamingContainer whose client ID changes (for example, UIData). However, even in these cases, consecutive calls to this method must always return the same value. The implementation must follow these steps in determining the clientId:
Find the closest ancestor to this component in the view hierarchy that implements NamingContainer. Call getContainerClientId() on it and save the result as the parentId local variable. Call getId() on this component and save the result as the myId local variable. If myId is null, call context.getViewRoot().createUniqueId() and assign the result to myId. If parentId is non-null, let myId equal parentId + NamingContainer.SEPARATOR_CHAR + myId. Call Renderer.convertClientId(javax.faces.context.FacesContext, java.lang.String), passing myId, and return the result.
Parameters:
context - The FacesContext for the current request
Throws:
NullPointerException - if context is null -
9. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
nbelaevski Sep 16, 2008 9:03 AM (in response to igor_d)a4j:repeat is an example of
"igor_d" wrote:
NamingContainer whose client ID changes (for example, UIData) -
10. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
igor_d Sep 16, 2008 9:19 PM (in response to igor_d)Right, so there is no solution? Good :-(
Need a workaround then. -
11. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
abelevich Sep 17, 2008 12:38 PM (in response to igor_d)Try this code:
final FacesContext context = FacesContext.getCurrentInstance();
//Find UIRepeat componet before
if (component != null && (component instanceof UIRepeat)) {
final UIRepeat repeater = (UIRepeat)component;
Object rowKey = repeater.getRowKey();
repeater.captureOrigValue();
try {
DataVisitor visitor = new DataVisitor() {
public void process(FacesContext context, Object rowKey, Object argument) throws IOException {
repeater.setRowKey(rowKey);
ListIterator childIterator = repeater.getChildren().listIterator();
while (childIterator.hasNext()) {
UIComponent child = (UIComponent) childIterator.next();
if (Boolean.TRUE.equals(child.getAttributes().get(INPUT_REQUIRED))) {
OurJsfValidator.validateRequired(context, child);
}
}
}
};
repeater.walk(context, visitor, null);
} catch (IOException exception){
}finally{
repeater.restoreOrigValue(context);
repeater.setRowKey(rowKey);
}
} -
12. Re: Incorrect getClientId and getSubmittedvalue in Richfaces
igor_d Oct 6, 2008 7:38 PM (in response to igor_d)Anton, thanks for your help - really appreciate it! Good stuff!