I don't want to use an IComponentOnBeforeRenderListener as it is an application wide facility whereas what I'm doing applies to a couple of pages only.
But you suggestion gave me an idea. I am now using a behavior which I add to all form components in ListView#populateItem(). The behavior marks the components as invalid in onConfigure() which comes before onBeforeRender() and hence before the IComponentOnBeforeRenderListener. The problem with this solution is that this code is much more complicated than what I was doing originally. Now I have to put the validation errors in a transient field which is set in the form's onConfigure() method, and use this field to retrieve the errors from within Behavior#onConfigure(). What I tried to do originally was much cleaner, the model object was validated and the components invalidated from within a single method. It does seem like AbstractRepeater should have a postOnPopulate() method to allow client code to access the created components before onBeforeRender() is executed, don't you think? On Tue, Nov 25, 2014 at 4:29 PM, Martin Grigorov <[email protected]> wrote: > OK, but isn't it possible to mark the form components as invalid with > IComponentOnBeforeRenderListener too ? > Just add the new IComponentOnBeforeRenderListener in the collection before > FormErrorDecorator. > > Martin Grigorov > Wicket Training and Consulting > https://twitter.com/mtgrigorov > > On Tue, Nov 25, 2014 at 4:15 PM, mscoon <[email protected]> wrote: > > > attachValidationErrors has nothing to do with FormErrorDecorator. It is > > just some code that adds validation errors to some form components. > > > > I use it because I want to show validation errors right when then form > > opens, and not after a submit. For instance if the user loads a record > for > > editing, and this record has some wrong data in it, I want to immediately > > show the validation errors when the page renders and not have to wait > until > > a submit. > > > > On Tue, Nov 25, 2014 at 11:50 AM, Martin Grigorov <[email protected]> > > wrote: > > > > > Hi, > > > > > > On Mon, Nov 24, 2014 at 10:34 PM, mscoon <[email protected]> wrote: > > > > > > > Martin, > > > > > > > > I'll try once again to explain my problem and if it's still unclear > > I'll > > > > make the quickstart. > > > > > > > > What you say is right, the sequence of events is as you said. > > > > > > > > My problem is that everything happens in > > > AbstractRepeater#onBeforeRender(). > > > > So I have to put my code "attachValidationErrors" either before or > > after > > > > AbstractRepeater#onBeforeRender(). > > > > > > > > If I put it before, the form components have not yet been created > > > > (onPopulate() has not yet been called). > > > > > > > > If I put it after, the componentPostOnBeforeRenderListeners have > > already > > > > run so the ErrorDecorator thinks there are no errors. > > > > > > > > What I need is a way for my code to run *after* onPopulate() but > > *before* > > > > onBeforeRenderChildren(). There is no such hook though. > > > > > > > > Let me also expand my pseudocode a bit in case this helps: > > > > > > > > class MyPage extends WebPage { > > > > > > > > pyblic MyPage() { > > > > > > > > > > > > > > > Form form = new Form("form", model) { > > > > override onBeforeRender() { > > > > attachValidationErrors(); > > > > > > > > > > Why do you need to call that here at all ? Why you want to traverse the > > > sub-tree manually ? > > > > > > By using IComponentOnBeforeRenderListener you are being notified for > each > > > and every Component in the component tree. > > > So your listener should just check whether the component is an instance > > of > > > FormComponent and if its name matches (and the other complex logic you > > > have) then report the error. > > > > > > > > > > onBeforeRender(); > > > > } > > > > }; > > > > add(form); > > > > > > > > ListView list = new ListView("list", model2) { > > > > public populateItem(ListItem listItem) { > > > > add(new TextField("name", new PropertyModel(model2, > > "name"))); > > > > } > > > > } > > > > form.add(list); > > > > > > > > } > > > > > > > > void attachValidationErrors() { > > > > form.visitChildren(FormComponent.class, new > > > > IVisitor<FormComponent,Void>() { > > > > void component(FormComponent<?> obj, IVisit<Void> visit) { > > > > if (obj.getId().equals("name") /* and some other > complex > > > > logic here */) { > > > > obj.error("Please provide a name"); > > > > } > > > > } > > > > }); > > > > } > > > > > > > > I think this makes my problem quite evident. I can't find the right > > place > > > > to put the call to attachValidationErrors(). > > > > > > > > Or perhaps I need a different implements for FormErrorDecorator. > > > > > > > > > > > > > > > > On Mon, Nov 24, 2014 at 5:13 PM, Martin Grigorov < > [email protected] > > > > > > > wrote: > > > > > > > > > Hi, > > > > > > > > > > Maybe I miss something from your description but I think ListView's > > > items > > > > > should have their #onBeforeRender() method called as any other > > > component > > > > in > > > > > the tree. > > > > > > > > > > org.apache.wicket.markup.repeater.AbstractRepeater#onBeforeRender() > > > first > > > > > calls #onPopulate() (where ListView adds its children) and then > calls > > > > > super.onBeforeRender() > > > > > where org.apache.wicket.MarkupContainer#onBeforeRenderChildren() > that > > > > calls > > > > > #onBeforeRender() for all children components. So > > > > > IComponentOnBeforeRenderListener should be notified. > > > > > > > > > > Maybe a quickstart will make it easier for understanding where is > the > > > > > problem. > > > > > > > > > > > > > > > On Mon, Nov 24, 2014 at 4:52 PM, mscoon <[email protected]> wrote: > > > > > > > > > > > Martin, > > > > > > > > > > > > Application#getComponentPostOnBeforeRenderListeners is how I am > > > already > > > > > > registering my FormErrorDecorator. > > > > > > > > > > > > Attaching the validation errors after super.onBeforeRender() does > > not > > > > > work > > > > > > even for components that are statically added and not part of a > > list > > > > > view. > > > > > > > > > > > > Here's some psuedocode: > > > > > > > > > > > > Form form = new Form("form", model) { > > > > > > protected void onBeforeRender() { > > > > > > super.onBeforeRender(); > > > > > > attachValidationErrors(); > > > > > > } > > > > > > } > > > > > > > > > > > > super.onBeforeRender() calls onBeforeRender() on all children > which > > > in > > > > > turn > > > > > > calls both the componentPreOnBeforeRenderListeners and the > > > > > > componentPostOnBeforeRenderListeners. So by the time > > > > > > attachValidationErrors() is called the error decorator has run > and > > > > > finished > > > > > > (and done nothing as it found no errors). > > > > > > > > > > > > If I move attachValidationErrors before super.onBeforeRender(), > > then > > > it > > > > > > works for statically added form components. It does not work for > > > > > components > > > > > > within ListViews because populateItem has not yet been called. > > > > > > > > > > > > I could move some of the error attaching logic within > populateItem > > > but > > > > > this > > > > > > is ugly and leads to code duplication (as populateItem will not > > > always > > > > be > > > > > > called because I need setReuseItems(true)). > > > > > > > > > > > > Any other ideas? > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > On Mon, Nov 24, 2014 at 3:23 PM, Martin Grigorov < > > > [email protected] > > > > > > > > > > > wrote: > > > > > > > > > > > > > Hi, > > > > > > > > > > > > > > Try with org.apache.wicket.Application#getComponent*Post* > > > > > > > OnBeforeRenderListeners() > > > > > > > > > > > > > > Martin Grigorov > > > > > > > Wicket Training and Consulting > > > > > > > https://twitter.com/mtgrigorov > > > > > > > > > > > > > > On Mon, Nov 24, 2014 at 2:50 PM, mscoon <[email protected]> > > wrote: > > > > > > > > > > > > > > > Hi all, > > > > > > > > > > > > > > > > I am using a FormErrorDecorator that implements an > > > > > > > > IComponentOnBeforeRenderListener in order to automatically > > > attach a > > > > > css > > > > > > > > class to form components with validation errors (see > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > https://cwiki.apache.org/confluence/display/WICKET/Automatic+styling+of+form+errors > > > > > > > > ). > > > > > > > > > > > > > > > > Sometimes I want to manually add errors to form components > and > > I > > > > was > > > > > > > doing > > > > > > > > that in onBeforeRender() before the call to > > > > super.onBeforeRender(). I > > > > > > do > > > > > > > > this because sometimes the object being edited is in an > invalid > > > > state > > > > > > > and I > > > > > > > > want to show the validation errors right when the form opens > > and > > > > not > > > > > > > after > > > > > > > > a submit. This is working fine for most cases as the errors > are > > > > > > attached > > > > > > > to > > > > > > > > the form components before the FormErrorDecorator runs. > > > > > > > > > > > > > > > > However, form components inside a list view are not created > > until > > > > the > > > > > > end > > > > > > > > of ListView.onBeforeRender(). This means that I cannot attach > > > > errors > > > > > > > before > > > > > > > > this step because the list view items don't yet exist, and > if I > > > > > attach > > > > > > > them > > > > > > > > after onBeforeRender they are not picked up by the > > > > > FormErrorDecorator. > > > > > > > > > > > > > > > > Any ideas? > > > > > > > > > > > > > > > > Thanks, > > > > > > > > Marios > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
