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


--
Mit freundlichen Grüßen,
------------------------------------------------------------------------
*Christian Beikov*

Reply via email to