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 > > > > > > > > > > > > > > > > > > > > > > > > > > > >
