Hi,
thanks to Martin and Christan for your answers.
Trinidad and primefaces are not used in my project so far.
I had a quick look and it seems that the tr:resetActionListener as well
as the primefaces extension must be attached to all commands and I have
nearly 600. So I am looking for a more generic way.
Christias solution did not work in detail in combination with richfaces
4.2.Final.
The renderIds are not full qualified client ids and therefore component
lookups fail.
Moreover I would not reset self-rendered outputpanels with this approach.
But I have a workaorund now.
I use also a PhaseListener that runs afterRestoreView phase over the
complete view tree(!) and resets all EditableValueOlders.
At first I thought this would cost too much performance to run over the
complete view and to do it on every request.
But to my surprise it takes only one millisecond on my dev machine.
However I would prefer to reset only submitted components and only in
case of a validation/conversion error after rendering the invalid values
and before state saving. From my pov this should be done always
internally in JSF.
Or does it make any sense to keep the local/submitted values after a
conversion/validation error occured and after the response is rendered?
Thanks again,
Michael
Am 26.03.2012 17:35, schrieb Christian Beikov:
Hey,
the following PhaseListener implementation will do the trick, at least
this is what I would expect that should be done by jsf in general.
public class ResetInputPhaseListener implements PhaseListener {
private static final Logger log =
LoggerFactory.getLogger(ResetInputPhaseListener.class);
@Override
public void afterPhase(PhaseEvent pe) {
if
(pe.getFacesContext().getPartialViewContext().isAjaxRequest()) {
Collection<String> renderIds =
pe.getFacesContext().getPartialViewContext().getRenderIds();
UIViewRoot view = pe.getFacesContext().getViewRoot();
for (String renderId : renderIds) {
UIComponent comp = findComponent(view, renderId);
if (comp != null) {
recursiveReset(comp);
} else {
log.warn("Could not find component with id '" +
renderId + "' in view '" + view.getViewId() + "'");
}
}
}
}
/**
* Originally taken from Mojarra implementation of UIComponentBase
with the
* addition of special checking when the NamingContainer is of the
type UIForm.
*/
private UIComponent findComponent(UIComponent comp, String expr) {
if (expr == null) {
throw new NullPointerException();
}
FacesContext ctx = FacesContext.getCurrentInstance();
final char sepChar = UINamingContainer.getSeparatorChar(ctx);
final String SEPARATOR_STRING = String.valueOf(sepChar);
if (expr.length() == 0) {
// if an empty value is provided, fail fast.
throw new IllegalArgumentException("\"\"");
}
// Identify the base component from which we will perform our
search
UIComponent base = comp;
if (expr.charAt(0) == sepChar) {
// Absolute searches start at the root of the tree
while (base.getParent() != null) {
base = base.getParent();
}
// Treat remainder of the expression as relative
expr = expr.substring(1);
} else if (!(base instanceof NamingContainer)) {
// Relative expressions start at the closest
NamingContainer or root
while (base.getParent() != null) {
if (base instanceof NamingContainer) {
break;
}
base = base.getParent();
}
}
// Evaluate the search expression (now guaranteed to be relative)
UIComponent result = null;
String[] segments = expr.split(SEPARATOR_STRING);
for (int i = 0, length = (segments.length - 1);
i < segments.length;
i++, length--) {
result = findComponent(base, segments[i], (i == 0));
// the first element of the expression may match base.id
// (vs. a child if of base)
if (i == 0 && result == null
&& segments[i].equals(base.getId())) {
result = base;
}
if (result != null && (!(result instanceof
NamingContainer)) && length > 0) {
throw new IllegalArgumentException(segments[i]);
}
if (result == null) {
break;
}
base = result;
}
// Return the final result of our search
return (result);
}
private UIComponent findComponent(UIComponent base, String id,
boolean checkId) {
if (checkId && id.equals(base.getId())) {
return base;
}
// Search through our facets and children
UIComponent result = null;
for (Iterator i = base.getFacetsAndChildren(); i.hasNext();) {
UIComponent kid = (UIComponent) i.next();
// Special handling for UIForm because of the attribute
prependId
if (!(kid instanceof NamingContainer) || (kid instanceof
UIForm && !((UIForm) kid).isPrependId() && !id.equals(kid.getId()))) {
if (checkId && id.equals(kid.getId())) {
result = kid;
break;
}
result = findComponent(kid, id, true);
if (result != null) {
break;
}
} else if (id.equals(kid.getId())) {
result = kid;
break;
}
}
return (result);
}
private void recursiveReset(UIComponent comp) {
if (comp instanceof EditableValueHolder) {
((EditableValueHolder) comp).resetValue();
}
for (Iterator<UIComponent> i = comp.getFacetsAndChildren();
i.hasNext();) {
recursiveReset(i.next());
}
}
@Override
public void beforePhase(PhaseEvent pe) {
}
@Override
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
}
Am 26.03.2012 17:22, schrieb Martin Koci:
Hi,
normal JSF behaviour (as you already know) is preserving and
resdisplaying the invalid input to allow re-type it later, for example:
'"12-14-200001" can be understood as date': a user can fix it with
minimal effort only by removing two additional zeros.
The classic solution for your problem is [1] tr:resetActionListener or
[2] pe:resetEditableValues. Do those two solve your task or is it other
problem?
a) How do I get the JSF 1.2 behavior with 2.1? Is resetValue() the
wrong method?
This is the right method.
b) Ideally I would reset only the executed components instead of all
input fields of the form. How can I determine them?
With richfaces 3.3.3 I checked for request keys representing the
submitted region or the ajaxSingle key. is there anything similar for
ajax commands and JSF 2.1?
for example pe:resetEditableValues has attribute 'for' or the standard
key javax.faces.partial.execute says it.
c) Shouldn't there be out of the box support for this szenario?
Yes, in JSF 2.2 will be such thing as pe:resetEditableValues in core (in
prefix f:)
[1]
http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_resetActionListener.html
[2]
http://fractalsoft.net/primeext-showcase-mojarra/views/resetEditableValues.jsf
Michael Heinen píše v Po 26. 03. 2012 v 15:22 +0200:
So I would like to clear the component values AFTER rendering and
BEFORE
state saving.
Is this possible at all?
Or do I have any better alternatives with JSF 2.1?
Thanks,
Michael
Am 26.03.2012 13:49, schrieb Michael Heinen:
Hi all,
I refer to the problem described at:
https://cwiki.apache.org/confluence/display/MYFACES/Clear+Input+Components#
Workflow:
1) Form is submitted
2) Validation or conversion fails
3) Another command is clicked that loads new or "fresh" data into the
same area
Problem:
The data of request (1) is shown instead of (3) because the submitted
or local values of the components are not cleared after
validation/conversion error.
Solution for JSF 1.2
I patched com.sun.facelets.FaceletViewHandler and cleared the UIInput
components via resetValue() before the new state was saved.
As a result new (fresh) data was shown correctly and the submitted
value was also shown directly after the validation/conversion error.
With JSF 2.1 this does not work the same way.
- I patched
org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView
- Before accessing the state manager I iterate over the
clientIdsWithMessages, determine the correspoding form and call
resetValue for all inputComponents.
- As a result new (fresh) data is shown correctly after step (3)
- But the submitted value is NOT shown directly after the
validation/conversion error (step 2). Instead the original value is
shown.
(e.g. User clears required value and submits form, message 'Field
must not be empty' is shown and field contains the original value
instead of being empty)
Questions:
a) How do I get the JSF 1.2 behavior with 2.1? Is resetValue() the
wrong method?
b) Ideally I would reset only the executed components instead of all
input fields of the form. How can I determine them?
With richfaces 3.3.3 I checked for request keys representing the
submitted region or the ajaxSingle key. is there anything similar for
ajax commands and JSF 2.1?
c) Shouldn't there be out of the box support for this szenario?
Used versions:
MyFaces 2.1.6 with partial state saving activated
Tomahawk2 1.1.11
Richfaces 4.2.0 Final
Regards,
Michael