Specify the phaselistener as global one in the facesconfig.xml and adapt the findComponent method to ignore naming containers when looking for the render-ids then every use case should be handeled by the listener and everything should work as expected.
Regards, Christian Am 28.03.2012 18:13 schrieb "Michael Heinen" <[email protected]>: > Afaik these global ActionListeners are not called for behaviors (f:ajax or > a4j:ajax attached to a component) so it would not work for all kind of ajax > requests. Is this correct? > > In my case it does also not help to run only over the parent form of the > command which submitted the request because I have multiple forms on my > pages. A command could render areas inside other forms and those > EditableValueHolders would not be reset with this approach in subsequent > requests. > > I can run over the submitted form only during the request that results in > a valdiation/conversion error but in this case the INVOKE_APPLICATION phase > is not invoked. That's the dilemma. > > So I'll change my "ResetInputPhaseListener" from after RESTORE_VIEW to > before INVOKE_APPLICATION for better state handling. > > Thanks, > Michael > > > > Am 28.03.2012 16:42, schrieb Martin Koci: > >> Michael Heinen píše v St 28. 03. 2012 v 16:22 +0200: >> >>> 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. >>> >> Interesting requirement. >> Try custom ActionListenerImpl. The default implementation is [1]. This >> code implements the "action" feature at h:commandButton/link. You can >> provide own implementation, find parent UIForm and clear all >> EditableValueHolder in this UIForm. This is generally faster as >> interating over whole UIViewRoot. Also submittedValues are part of >> application state and manipulation of those value is responsibility of >> invoke-application phase. >> Register your implementation in faces-config.xml as: >> >> <application> >> <action-listener>my.reset.**action.Listener</action-**listener> >> </application> >> >> >> [1] >> https://svn.apache.org/repos/**asf/myfaces/core/trunk/impl/** >> src/main/java/org/apache/**myfaces/application/**ActionListenerImpl.java<https://svn.apache.org/repos/asf/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ActionListenerImpl.java> >> >> 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<http://myfaces.apache.org/trinidad/trinidad-api/tagdoc/tr_resetActionListener.html> >>>>> >>>>> [2] >>>>> http://fractalsoft.net/**primeext-showcase-mojarra/** >>>>> views/resetEditableValues.jsf<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#<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 >>>>>>> >>>>>> >> >> >

