I've been working on this off and on for a couple days now and can't quite get it to work as I would expect. I've looked through many examples but I must be misunderstanding something.
What I have is a Bootstrap Modal that get's loaded with a partial view. What I'm trying to do is have validation (hopefully client side) with any errors being dispalyed in the @ValidationSummary in the Modal. The biggest issue I'm having is that when there is an error, instead of showing in the original modal it basically loads the modal partial view in a new page. The validation summary is populated correctly but it doesn't have any styling plus it isn't in the modal at that point.
*Note: I'm not using AJAX to load the modal at the moment. I will eventually get that but I'm not as comfortable with AJAX yet and i want to get it working first, then I can come back and refactor in AJAX.
_Layout.cshtml - I found an example that said I needed to load the JS.unobtrusive when loading the Modal. I'm assuming I'm doing that correctly but I might be missing something there.
<div id="modal-container" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
</div>
</div>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
<script type="text/javascript">
//**** Bootstrap Modal - used with Partial Views ***********************
$(function () {
// Initalize modal dialog
// attach modal-container bootstrap attributes to links with .modal-link class.
// when a link is clicked with these attributes, bootstrap will display the href content in a modal dialog.
$('body').on('click', '.modal-link', function (e) {
e.preventDefault();
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
//load the unobtrusive JS code
$jQval.unobtrusive.parse($modal-container);
var $form = $modal-container.find("form");
$.validator.unobtrusive.parse($form);
});
// Attach listener to .modal-close-btn's so that when the button is pressed the modal dialog disappears
$('body').on('click', '.modal-close-btn', function () {
$('#modal-container').modal('hide');
});
//clear modal cache, so that new content can be loaded
$('#modal-container').on('hidden.bs.modal', function () {
$(this).removeData('bs.modal');
});
$('#CancelModal').on('click', function () {
return false;
});
});
_PasswordReset.cshtml
div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4>Reset your Password</h4>
</div>
<div class="modal-body">
<div class="form-horizontal">
@using (Html.BeginForm("PasswordReset", "Member", FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(false, "", new { @class = "alert alert-danger" })
<!-- BEGIN HIDDEN FIELDS AREA -->
@Html.HiddenFor(model => model.MemberId)
<!-- END HIDDEN FIELDS AREA -->
<div class="form-group">
<label class="control-label col-xs-3">Password</label>
<div class="col-md-9">
@Html.TextBoxFor(c => c.Password, new { Class = "form-control", placeholder = "New Password", autofocus = "" })
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-3">Confirm</label>
<div class="col-md-9">
@Html.TextBoxFor(c => c.PasswordConfirm, new { Class = "form-control", placeholder = "Confirm Password" })
</div>
</div>
<div class="form-group">
<div class="col-xs-offset-3 col-xs-9">
<button type="submit" id="approve-btn" class="btn btn-primary">
Reset
</button>
<input type="button" class="btn btn-default" value="Cancel" data-dismiss="modal" />
</div>
</div>
}
</div>
</div>
Controller - I'm assuming that if the model is not valid then I'm supposed to pass back a PartialView since that is what I loaded into the Modal initially?
public ActionResult PasswordReset(MemberViewModel vm)
{
MemberPasswordReset model = new MemberPasswordReset();
model.MemberId = vm.MemberId;
return PartialView("_PasswordReset", model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async System.Threading.Tasks.Task<ActionResult> PasswordReset(MemberPasswordReset model)
{
if (!ModelState.IsValid)
{
return PartialView("_PasswordReset", model);
}
ApplicationDbContext context = new ApplicationDbContext();
UserStore<ApplicationUser> userStore = new UserStore<ApplicationUser>(context);
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(userStore);
String userId = User.Identity.GetUserId();
String hashedNewPassword = UserManager.PasswordHasher.HashPassword(model.Password);
ApplicationUser currentUser = await userStore.FindByIdAsync(userId);
await userStore.SetPasswordHashAsync(currentUser, hashedNewPassword);
await userStore.UpdateAsync(currentUser);
return RedirectToAction("MyAccount");
}
ViewModel
public class MemberPasswordReset
{
public string Password { get; set; }
[Compare("Password", ErrorMessage = "Confirm password doesn't match.")]
public string PasswordConfirm { get; set; }
public int MemberId { get; set; }
}
Bundle.config
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js",
"~/Scripts/jquery.validate.js",
"~/Scripts/jquery.validate.unobtrusive.js"));