Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about submitting forms on pages that use the generic "PageViewModel" #112

Open
Clink50 opened this issue Sep 14, 2023 · 6 comments

Comments

@Clink50
Copy link

Clink50 commented Sep 14, 2023

On our Home Page, we have the header, footer, metadata etc, which is all handled through the PageViewModel, but let's say that the page has a form on it that takes your name and age and a button to submit the form. If you leave the name blank, an validation error message should display that says that it's required. If the Home page has a model like @model PageViewModel<MyFormViewModel> when I submit the form, I not only have to bind the values for the name and age, but I also would have to bind all the values for PageViewModel, right? Because when the !ModelState.IsValid I have to return View("Index", model) where model has to be the entire PageViewModel.

Hopefully this makes sense, but basically I'm asking, if I have content that is managed by our marketing team and it needs to display on the Home page as well as have a form, how am I supposed to handle the form request and submission through MVC? I could do it all through JS, but I feel that defeats the purpose.

@seangwright
Copy link
Member

The forms submit via javascript, so any rendered state on the page is persisted while the form submits.
The form validation logic on the backend will then send a response with the re-rendered fields and validation messages, which is patched into the DOM.

Submission Request (XHR)

image

Submission Response (HTML)

image

@Clink50
Copy link
Author

Clink50 commented Sep 14, 2023

Thanks for the quick response! So it's submitted through javascript then, I see. I was hoping to use the MVC way to submit the forms. I think I've almost gotten it, but would like your feedback to see if I should continue this way, or just use javascript.

So the model is @model PageViewModel<MyFormViewModel>, and I have a form tag with an action of /Home/Submit. In the Submit action, I take in the PageViewModel<MyFormViewModel> as a parameter, and check for !ModelState.IsValid. When that the model is invalid, I get the pageDataContext.Metadata from the TryRetrieve call and then call GetPageViewModel with the metadata and the MyFormViewModel. And finally return View("Index", viewModel);

[HttpPost]
public IActionResult Submit(PageViewModel<MyFormViewModel> model)
{
    if (!ModelState.IsValid) 
    {
        return DefaultViewWithErrorMessage(model.Data);
    }

    // ...success logic
}

private IActionResult DefaultViewWithErrorMessage(MyFormViewModel model)
{
    if (_pageDataContextRetriever.TryRetrieve<CMS.DocumentEngine.Types.Website.MyBasePage>(out var pageDataContext)
        && pageDataContext.Page != null)
    {
        var myModel = GetPageViewModel(pageDataContext.Metadata, model);

        return View(nameof(this.Index), myModel);
    }

    // ...do something if it can't retrieve the page data context
}

@seangwright
Copy link
Member

Any forms created through the Form Builder feature will auto submit with JavaScript and this is by-design.

If you create your own custom MVC forms - like for login/register or something more complex than what the Form Builder can handle - you can handle submitting them however you want.

The two most common approaches:

  1. Use the PRG (POST-REDIRECT-GET) pattern using TempData
  2. Submit via JS using

PRG can require a lot of mechanical pieces to set up with MVC (it's a little easier with Razor Pages), but if you want a solution that doesn't require JavaScript, it's probably your best option - and it works with Xperience's Page Builder.

If you are ok requiring JavaScript, then the HTMX route is my favorite - it's very elegant, doesn't require any custom JS (just use the HTMX JS and .NET libraries), and is much lighter weight than jQuery's solution.

@Clink50
Copy link
Author

Clink50 commented Sep 15, 2023

For this particular case, it is a custom form that's on our Home page.

We basically took the MedioClinic solution as a starter project for ours, and we are building our site on top of that. So I was trying to get a better understanding on how the Form submission works when you have to return not just a MyFormViewModel, but the entire PageViewModel<MyFormViewModel>.

I'll keep researching and working on the direction I'm going with for now just to see if I can get it to work, but I'll also try it out the JS way and pick the best option.

I would to try out HTMX, but we won't be able to use it for this project.

@seangwright
Copy link
Member

Here's a code example of how the PRG architecture is implemented in an KX13 project.

There's a couple interacting pieces that you'll need to add to your project to get the full functionality, but you can see how it all comes together in the RegistrationController which uses this pattern.

@KenticoDevTrev
Copy link

KenticoDevTrev commented Sep 15, 2023

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants