Nested Forms in 1.4.x - order of calling onSubmit

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Nested Forms in 1.4.x - order of calling onSubmit

Bruno Borges
I wrote this message to the Users list but I now I think it would be better
to ask the devs

...

After playing with Nested Forms in WIcket 1.4.18, I found out that the
onSubmit method of these forms is called at the end of the process.

If a parent form has a button and this button is submited, its onSubmit
method is called before anything.
Then, parent form's onSubmit method is called.
Then, it will navigate through all nested forms calling their onSubmit
method.
The problem is that I have a nested forms that changes a value in the model
that is associated with the parent form.

My usecase has an AddressPanel with a form inside that manipulates the
"person.address" object. This panel is created by informing two
IModel<Address> objects.
One is to be used as the Person's address. The other one is to be used as
copy of, because of a CheckBox that states "Use the same address as of
account holder".

On its onSubmit method, is where I clone the account holder address to the
actual person.address.

But because of the order of how Wicket calls onSubmit methods, this
implementation fails.

Any suggestion?

Should Wicket call all nested forms' onSubmit methods before calling the
Button's onSubmit (or the parent form onSubmit) ?

Thanks,

*Bruno Borges*
(21) 7672-7099
*www.brunoborges.com*
Reply | Threaded
Open this post in threaded view
|

Re: Nested Forms in 1.4.x - order of calling onSubmit

tetsuo
This (nested first) is the behavior for 1.5.

In 1.4, you could override the 'Form.delegateSubmit()' method,
rewriting its logic to execute forms in reverse order, **IF**
'Form.onSubmit()' wasn't protected (thus, you can't call it on nested
forms from your form subclass).

You can, however, use reflection to cheat :)


@SuppressWarnings("rawtypes")
public class HomePage extends WebPage {

    public HomePage(final PageParameters parameters) {
        class SelfLoggingForm extends Form {
            public SelfLoggingForm(String id) {
                super(id);
                add(new Button("s"));
            }
            @Override
            protected void onSubmit() {
                System.out.println(this.getId());
            }
            @Override
            protected void delegateSubmit(IFormSubmittingComponent
submittingComponent)
            {
                // when the given submitting component is not null, it
means that it was the
                // submitting component
                Form<?> formToProcess = this;
                if (submittingComponent != null)
                {
                    // use the form which the submittingComponent has
submitted for further processing
                    formToProcess = submittingComponent.getForm();
                    submittingComponent.onSubmit();
                }

                // this list will hold the forms for execution in reverse order
                final List<Form<?>> forms = new ArrayList<Form<?>>();

                // Model was successfully updated with valid data
                forms.add(formToProcess);

                // call onSubmit on nested forms
                formToProcess.visitChildren(Form.class, new IVisitor<Form<?>>()
                {
                    public Object component(Form<?> component)
                    {
                        Form<?> form = component;
                        if (form.isEnabledInHierarchy() &&
form.isVisibleInHierarchy())
                        {
                            forms.add(form);
                            return IVisitor.CONTINUE_TRAVERSAL;
                        }
                        return IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
                    }
                });

                Collections.reverse(forms);
                for (Form<?> form : forms) {
                    invokeOnSubmit(form);
                }
            }

            private void invokeOnSubmit(Form<?> form) {
                try {
                    final Method onSubmitMethod =
Form.class.getDeclaredMethod("onSubmit", new Class[0]);
                    onSubmitMethod.setAccessible(true);
                    onSubmitMethod.invoke(form);
                } catch (Exception ex) {
                    throw new IllegalStateException(ex.getMessage(), ex);
                }
            }
        }

        add(new SelfLoggingForm("a")
            .add(new SelfLoggingForm("b")
                .add(new SelfLoggingForm("c"))));
    }
}

<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
  <form wicket:id="a">
    <form wicket:id="b">
      <form wicket:id="c">
        <button type="submit" wicket:id="s">C</button>
      </form>
      <button type="submit" wicket:id="s">B</button>
    </form>
    <button type="submit" wicket:id="s">A</button>
  </form>
</body>
</html>


On Wed, Oct 19, 2011 at 6:30 PM, Bruno Borges <[hidden email]> wrote:

> I wrote this message to the Users list but I now I think it would be better
> to ask the devs
>
> ...
>
> After playing with Nested Forms in WIcket 1.4.18, I found out that the
> onSubmit method of these forms is called at the end of the process.
>
> If a parent form has a button and this button is submited, its onSubmit
> method is called before anything.
> Then, parent form's onSubmit method is called.
> Then, it will navigate through all nested forms calling their onSubmit
> method.
> The problem is that I have a nested forms that changes a value in the model
> that is associated with the parent form.
>
> My usecase has an AddressPanel with a form inside that manipulates the
> "person.address" object. This panel is created by informing two
> IModel<Address> objects.
> One is to be used as the Person's address. The other one is to be used as
> copy of, because of a CheckBox that states "Use the same address as of
> account holder".
>
> On its onSubmit method, is where I clone the account holder address to the
> actual person.address.
>
> But because of the order of how Wicket calls onSubmit methods, this
> implementation fails.
>
> Any suggestion?
>
> Should Wicket call all nested forms' onSubmit methods before calling the
> Button's onSubmit (or the parent form onSubmit) ?
>
> Thanks,
>
> *Bruno Borges*
> (21) 7672-7099
> *www.brunoborges.com*
>
Reply | Threaded
Open this post in threaded view
|

Re: Nested Forms in 1.4.x - order of calling onSubmit

Bruno Borges
I thought about overriding that method...

Decided not to do it though to not have a different behaviour only in a
specific case. We fixed it by updating the model at validation stage, if
everything is valid().

It's working... :-)

I asked this mostly because I wanted to know if this submition process has
changed in 1.5.

It's a new world now, it's a new world...

And you are correct Martijn, they are not that bad at all

Thank you!

*Bruno Borges*
(21) 7672-7099
*www.brunoborges.com*



On Thu, Oct 20, 2011 at 1:44 PM, tetsuo <[hidden email]> wrote:

> This (nested first) is the behavior for 1.5.
>
> In 1.4, you could override the 'Form.delegateSubmit()' method,
> rewriting its logic to execute forms in reverse order, **IF**
> 'Form.onSubmit()' wasn't protected (thus, you can't call it on nested
> forms from your form subclass).
>
> You can, however, use reflection to cheat :)
>
>
> @SuppressWarnings("rawtypes")
> public class HomePage extends WebPage {
>
>    public HomePage(final PageParameters parameters) {
>        class SelfLoggingForm extends Form {
>            public SelfLoggingForm(String id) {
>                super(id);
>                add(new Button("s"));
>            }
>            @Override
>            protected void onSubmit() {
>                System.out.println(this.getId());
>            }
>            @Override
>            protected void delegateSubmit(IFormSubmittingComponent
> submittingComponent)
>            {
>                // when the given submitting component is not null, it
> means that it was the
>                // submitting component
>                Form<?> formToProcess = this;
>                if (submittingComponent != null)
>                {
>                    // use the form which the submittingComponent has
> submitted for further processing
>                    formToProcess = submittingComponent.getForm();
>                    submittingComponent.onSubmit();
>                }
>
>                // this list will hold the forms for execution in reverse
> order
>                final List<Form<?>> forms = new ArrayList<Form<?>>();
>
>                // Model was successfully updated with valid data
>                forms.add(formToProcess);
>
>                // call onSubmit on nested forms
>                formToProcess.visitChildren(Form.class, new
> IVisitor<Form<?>>()
>                {
>                    public Object component(Form<?> component)
>                    {
>                        Form<?> form = component;
>                        if (form.isEnabledInHierarchy() &&
> form.isVisibleInHierarchy())
>                        {
>                            forms.add(form);
>                            return IVisitor.CONTINUE_TRAVERSAL;
>                        }
>                        return
> IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
>                    }
>                });
>
>                Collections.reverse(forms);
>                for (Form<?> form : forms) {
>                    invokeOnSubmit(form);
>                }
>            }
>
>            private void invokeOnSubmit(Form<?> form) {
>                try {
>                    final Method onSubmitMethod =
> Form.class.getDeclaredMethod("onSubmit", new Class[0]);
>                    onSubmitMethod.setAccessible(true);
>                    onSubmitMethod.invoke(form);
>                } catch (Exception ex) {
>                    throw new IllegalStateException(ex.getMessage(), ex);
>                }
>            }
>        }
>
>        add(new SelfLoggingForm("a")
>            .add(new SelfLoggingForm("b")
>                .add(new SelfLoggingForm("c"))));
>    }
> }
>
> <html xmlns:wicket="
> http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
> <body>
>  <form wicket:id="a">
>    <form wicket:id="b">
>      <form wicket:id="c">
>        <button type="submit" wicket:id="s">C</button>
>      </form>
>      <button type="submit" wicket:id="s">B</button>
>    </form>
>    <button type="submit" wicket:id="s">A</button>
>  </form>
> </body>
> </html>
>
>
> On Wed, Oct 19, 2011 at 6:30 PM, Bruno Borges <[hidden email]>
> wrote:
> > I wrote this message to the Users list but I now I think it would be
> better
> > to ask the devs
> >
> > ...
> >
> > After playing with Nested Forms in WIcket 1.4.18, I found out that the
> > onSubmit method of these forms is called at the end of the process.
> >
> > If a parent form has a button and this button is submited, its onSubmit
> > method is called before anything.
> > Then, parent form's onSubmit method is called.
> > Then, it will navigate through all nested forms calling their onSubmit
> > method.
> > The problem is that I have a nested forms that changes a value in the
> model
> > that is associated with the parent form.
> >
> > My usecase has an AddressPanel with a form inside that manipulates the
> > "person.address" object. This panel is created by informing two
> > IModel<Address> objects.
> > One is to be used as the Person's address. The other one is to be used as
> > copy of, because of a CheckBox that states "Use the same address as of
> > account holder".
> >
> > On its onSubmit method, is where I clone the account holder address to
> the
> > actual person.address.
> >
> > But because of the order of how Wicket calls onSubmit methods, this
> > implementation fails.
> >
> > Any suggestion?
> >
> > Should Wicket call all nested forms' onSubmit methods before calling the
> > Button's onSubmit (or the parent form onSubmit) ?
> >
> > Thanks,
> >
> > *Bruno Borges*
> > (21) 7672-7099
> > *www.brunoborges.com*
> >
>