I have a page with multiple forms, each as a partial. I want to post each partial on submit. If there are errors, I want the validation errors to show in the partial as part of the main page i.e. I don't want to just see the partial on it's own page if there are errors. Am I correct in saying this behavior is only possible with an ajax post? How would I return the model state errors WITHOUT an ajax post, just a normal form post?
Edit: Still seeing the partial on it's own page
Partial -
@using (Html.BeginForm("Login", "Account", FormMethod.Post, new { id = "LoginForm" }))
{
@Html.ValidationMessage("InvalidUserNamePassword")
<fieldset class="fieldset">
<div>
<label for="form-field-user_id">User ID</label>
<span>
@Html.TextBoxFor(x => x.Username, new { @class = "form-field__input form-field__input--text", @id = "form-field-user_id"})
</span>
</div>
</fieldset>
<div class="form-field__button">
<button id="loginButton" type="submit" class="button button--primary">Login</button>
</div>
}
<script>
$('#loginButton').click(function () {
$.ajax({
type: "POST",
url: '@Url.Action("Login", "Account")',
data: $('form').serialize(),
success: function (result) {
if (result.redirectTo) {
window.location.href = result.redirectTo;
} else {
$("#LoginForm").html(result);
}
},
error: function () {
$("#LoginForm").html(result);
}
});
});
</script>
Controller -
[HttpPost]
public ActionResult Login(LoginModel model)
{
if (!ModelState.IsValid)
{
return PartialView("~/Views/Account/_Login.cshtml", model);
}
return Json(new { redirectTo = Url.Action("Index", "Profile") });
}
Yes, you are correct in saying this behavior is only possible with an ajax post.
There are a few problems with your current script meaning that you will not get the desired results.
Firstly your button is a submit button meaning that it will do a normal submit in addition to the ajax call unless you cancel the default event (by adding
return false;
as the last line of code in your script). However it would be easier to just change the button type totype="button"
The ajax call will now update the existing page, however it will add the returned partial inside the existing
<form>
element resulting in nested forms which is invalid html and not supported. Change your html to wrap the main views form in another elementand then modify the script to update the html of the outer element
Finally, your rendering dynamic content so client side validation will not work for the returned form. Assuming your properties have validation attributes (for example the
[Required]
attribute on theUserame
property), you need to reparse the validator after loading the contentYou noted that you have multiple forms on the page, in which case your ajax options should be
or if your declare
var form = $('#LoginForm');
as per the above snippet, thendata: form.serialize(),
to ensure you are serializing the correct form.Side note: There is no real need to change the
id
attribute of the textbox (it will beid=Username"
by default and you can simply useor just
@Html.LabelFor(x => x.UserName)
of the property is decorated with[Display(Name = "User ID")]