Page tree
Skip to end of metadata
Go to start of metadata

When you have multiple forms on the same page all submitting to the page you'll notice that all their controllers treat the request and handle their forms being submitted.

The solution is to use pre-execution to target a specific controller. The documentation on pre-execution has more details on this.

It's not quite that simple though when you have multiple forms on the same page. When you add validation and instead of returning a redirect return a view with validation errors, then the page is rendered in its entirety including the second controller. The pre-executed controller is executed first, then the rendering engine proceeds rendering the entire page. The view returned by the pre-executed controller is rendered into place on the page. During this process the second controller sees that its a POST request and treats it as if its form was submitted. The way you solve this is by treating the request as a form submission and do validation only during pre-execution. Then a POST request not during pre-execution instead renders the form as it would for a GET request.

This is an example of ContactFormComponent from the Blossom sample using this technique. Note how the handleSubmit method bridges over to the viewForm method unless its being pre-executed.

Using PreexecutionUtils in Blossom versions 3.0.5 or later, or 2.0.7 or later:

    @RequestMapping(value = "/contact", method = RequestMethod.GET)
    public String viewForm(@ModelAttribute ContactForm contactForm) {
        return "components/contactForm.ftl";
    }

    @RequestMapping(value = "/contact", method = RequestMethod.POST)
    public String handleSubmit(@ModelAttribute ContactForm contactForm, BindingResult result, Node content) throws RepositoryException {

        if (!PreexecutionUtils.isPreexecuting())
            return viewForm(contactForm);


        new ContactFormValidator().validate(contactForm, result);
        if (result.hasErrors()) {
            return "components/contactForm.ftl";
        }

        return "website:" + content.getProperty("successPage").getString();
    }

Earlier versions:

    @RequestMapping(value = "/contact", method = RequestMethod.GET)
    public String viewForm(@ModelAttribute ContactForm contactForm) {
        return "components/contactForm.ftl";
    }

    @RequestMapping(value = "/contact", method = RequestMethod.POST)
    public String handleSubmit(@ModelAttribute ContactForm contactForm, BindingResult result, Node content) throws RepositoryException {

        PreexecutionContext preexecutionContext = PreexecutionContextHolder.get(MgnlContext.getWebContext().getRequest());
        Node currentContentNode = MgnlContext.getAggregationState().getCurrentContentNode();
        if (preexecutionContext == null || !preexecutionContext.getUuid().equals(currentContentNode.getIdentifier()))
            return viewForm(contactForm);

        new ContactFormValidator().validate(contactForm, result);
        if (result.hasErrors()) {
            return "components/contactForm.ftl";
        }

        return "website:" + content.getProperty("successPage").getString();
    }