Open Clink50 opened 1 year ago
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.
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
}
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:
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.
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.
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.
Although you can copy it in, you can also just reference https://www.nuget.org/packages/XperienceCommunity.Baseline.Core.RCL/1.1.2
It's kentico agnostic and includes some core tools that you can leverage, including this.
Totally understand if you just want to grab the individual files though:
https://github.com/KenticoDevTrev/XperienceCommunity.Baseline/tree/master/src/Core/Core.RCL/Services https://github.com/KenticoDevTrev/XperienceCommunity.Baseline/tree/master/src/Core/Core.RCL/Attributes https://github.com/KenticoDevTrev/XperienceCommunity.Baseline/tree/master/src/Core/Core.RCL/Components/ImportModelState https://github.com/KenticoDevTrev/XperienceCommunity.Baseline/tree/master/src/Core/Core.RCL/Helpers
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 toreturn 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.