Server Side Field validation in .NET Core 3.1 MVC in modal popup not working - asp.net-core-mvc

I have a partial view within a modal popup. Client side field validation works, such as required fields. But there are some server side validations that don't present themselves whilst keeping the modal popup open.
For example, I create a new 'teacher band' and the controller checks for a duplicate band. When I press submit, the page actually browses to the partial view and presents the error in the validationsumary, rather than keeping it within the modal.
Controller -
public async Task<IActionResult> Add()
{
CreateTeacherBandViewModel model = new CreateTeacherBandViewModel();
return PartialView(model);
}
[HttpPost]
public async Task<IActionResult> Add(CreateTeacherBandViewModel model)
{
if (ModelState.IsValid)
{
if (await _teacherBandService.BandExists(model.BandName))
{
ModelState.AddModelError("", "A band with that name already exists");
return PartialView(model);
}
else
{
await _teacherBandService.Add(model);
return RedirectToAction("Index", "TeacherBand", null);
}
}
else
{
return PartialView();
}
}
Partial View
#model Models.CreateTeacherBandViewModel
<script src="~/assets/js/plugins/pickers/color/spectrum.js"></script>
<script src="~/assets/js/demo_pages/picker_color.js"></script>
#using (Html.BeginForm("Add", "TeacherBand", null))
{
<!-- Iconified modal -->
<div id="modal_addband" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title"><i class="icon-user-plus mr-2"></i> Add New Band</h5>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Name</label>
#Html.TextBoxFor(model => model.BandName, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.BandName)
</div>
<h6 class="font-weight-semibold">Charge Rates</h6>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label>AM</label>
#Html.TextBoxFor(model => model.DefaultChargeRateAM, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.DefaultChargeRateAM)
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>PM</label>
#Html.TextBoxFor(model => model.DefaultChargeRatePM, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.DefaultChargeRatePM)
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>Daily</label>
#Html.TextBoxFor(model => model.DefaultChargeRateDaily, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.DefaultChargeRateDaily)
</div>
</div>
</div>
<h6 class="font-weight-semibold">Pay Rates</h6>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label>AM</label>
#Html.TextBoxFor(model => model.DefaultPayRateAM, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.DefaultPayRateAM)
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>PM</label>
#Html.TextBoxFor(model => model.DefaultPayRatePM, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.DefaultPayRatePM)
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>Daily</label>
#Html.TextBoxFor(model => model.DefaultPayRateDaily, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.DefaultPayRateDaily)
</div>
</div>
</div>
<hr />
<div class="form-group">
<label>Colour</label>
#Html.TextBoxFor(model => model.Colour, new { #class = "form-control"})
#Html.ValidationMessageFor(model => model.Colour)
</div>
#Html.ValidationSummary()
<div class="modal-footer">
<button type="button" class="btn btn-link" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Create Band</button>
</div>
</div>
</div>
</div>
<!-- /iconified modal -->
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js">
</script>
}
Finally, the Index page that renders the partial view
#Html.Partial("Add", new CreateTeacherBandViewModel())

Related

Google Invisible Recaptcha - Enter press key not work

I implemented google invisible recaptcha on my login form but when i submit the form by pressing Enter key, it does not send any response token. However, when i clicked button whose type submit, it validates successfully.
How can I get response with both press enter and click button?
C# - MVC application used as technologhy. #Model.GoogleRecaptchaSiteKey property is filled on my application.
Here is my login form html
#using (Html.BeginForm("Login", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] }, FormMethod.Post, new { #class = "login-form", id = "login-form" }))
{
<div class="login-form">
<h3 class="form-title">Login Form</h3>
<div class="form-group">
<!--ie8, ie9 does not support html5 placeholder, so we just show field title for that-->
<label class="control-label visible-ie8 visible-ie9">Kullanıcı Adı</label>
<div class="input-group">
<div class="input-group-addon">
<i class="fa fa-user"></i>
</div>
#Html.TextBoxFor(f => f.UserName, new { title = "Kullanıcı adınızı giriniz.", #class = "form-control placeholder-no-fix", #placeholder = "Kullanıcı Adı", #value = "", #autofocus = "true" })
</div>
#Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">password</label>
<div class="input-group" id="show_hide_password">
<div class="input-group-addon">
<i class="fa fa-lock"></i>
</div>
#Html.TextBoxFor(f => f.Password, new { #title = "password.", #type = "password", #class = "form-control placeholder-no-fix", #placeholder = "password", #value = "" })
<div class="input-group-addon">
<i class="fa fa-eye-slash" id="i_show_hide_password" aria-hidden="true"></i>
</div>
</div>
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="form-actions">
#Html.AntiForgeryToken()
<input id="login" type="submit" class="btn green pull-right g-recaptcha" data-size="invisible" data-sitekey="#Model.GoogleRecaptchaSiteKey" data-callback="onSubmit" value="Login" />
#Html.ValidationMessage("reCaptcha")
<br />
</div>
</div>
}
Script is below here
function onSubmit(token) {
document.getElementById("login-form").submit();
}

Ajax.BeginForm submitting the form twice

I have a problem with my modal on inserting data. Every time I add a new row it get's a second identical row into the database. I don't really know exactly what I did wrong so if you have a ideea on how to solve this please help me.
This is my controller:
public ActionResult IndexEvent()
{
return View(db.tbl_Event.ToList());
}
[HttpGet]
public ActionResult AddEvent()
{
return PartialView();
}
[HttpPost]
public ActionResult AddEvent(BOL3.tbl_Event eve)
{
if(ModelState.IsValid)
{
db.tbl_Event.Add(eve);
db.SaveChanges();
}
return PartialView("_Detail", db.tbl_Event.ToList());
}
,here is my Index view, _Detail partial view and Add partial view (in the same order):
#model IEnumerable<BOL3.tbl_Event>
#{
ViewBag.Title = "Index";
}
<link href="#Url.Content("~/Content/bootstrap/css/bootstrap.min.css")" rel="stylesheet" />
<link href="#Url.Content("~/Content/bootstrap/css/bootstrap-theme.min.cs")" rel="stylesheet" />
<link href="#Url.Content("~/Content/bootstrap/css/font-awesome.min.cs")" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<div id="main-div">
<div class="clearfix"> </div>
<div class="clearfix"> </div>
<div class="container">
<i class="glyphicon glyphicon-plus"></i> Add New
<br />
<br />
<div id="div-record">
#Html.Partial("_Detail")
</div>
</div>
</div>
<div class="modal fade" id="Add-Model" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Add Event</h4>
</div>
<div class="divForAdd">
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#Add').click(function (event) {
event.preventDefault();
$.get(this.href, function (response) {
$('.divForAdd').html(response);
});
$('#Add-Model').modal({
backdrop: 'static',
}, 'show');
});
#model IEnumerable<BOL3.tbl_Event>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Event Name</th>
<th>Starting Event (Date and Time)</th>
<th>Ending Event (Date and time)</th>
<th>All Day ?</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
#foreach(var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Event)
</td>
<td>
#Html.DisplayFor(modelItem => item.Start_Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.End_Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.All_Day)
</td>
<td>
<i class="glyphicon glyphicon-pencil"></i> Edit
</td>
<td>
#Ajax.ActionLink(" Delete", "DeleteEvent", "Prog", new { #id = item.ID }, new AjaxOptions { HttpMethod = "GET", UpdateTargetId = "div-record" }, new { #class = "glyphicon glyphicon-trash" })
</td>
</tr>
}
</tbody>
</table>
</div>
#model BOL3.tbl_Event
#using (Ajax.BeginForm("AddEvent", "Prog", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "div-record", OnSuccess = "$('.close').click()" }))
{
<div class="modal-body">
<div class="row form-group">
<div class="col-md-12">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-pushpin"></i></span>
#Html.TextBoxFor(m => m.Event, new { #class = "form-control" })
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-12">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
#Html.TextBoxFor(m => m.Start_Date, new { #class = "form-control" })
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-12">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
#Html.TextBoxFor(m => m.End_Date, new { #class = "form-control" })
</div>
</div>
</div>
<div class="row form-group">
<div class="col-md-12">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
#Html.TextBoxFor(m => m.All_Day, new { #class = "form-control" })
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-success" name="cmd">Save</button>
</div>
}
I tried something else but that also gave me a problem (see this link: "Refresh table list using Ajax in Asp.Net Mvc") Thank you.
this problem is occuring because you have loaded <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script> twice in the _layout page as well as index page and because of that it causes ajax to send request twice. so remove the link either from Index page or _layout page
Why it causes to submit twice?
if you look at the code of unobtrusive-ajax it has function $(document).on("click", "form[data-ajax=true] which is responsible for sending the request so when you submit the form this function trigger's differently on each script you loaded which causes the request to send twice (if someone can explain better feel free to edit)
It is because you have JS function binded to element #Add and you are not disabling anchror href correctly, thus having two requests (since your anchor has link attribute as well). In this SO question How can I disable HREF if onclick is executed? you can se, that correct click handling should be like
$('#Add').click(function (event) {
event.preventDefault();
$.get(this.href, function (response) {
$('.divForAdd').html(response);
});
$('#Add-Model').modal({
backdrop: 'static',
}, 'show');
return false; // this is essential
});

Submit send values null in Ajax to Controller

I have several ajax.begin form within a Ajax.BeginForm "father".
The problem to the "parent" function or the first Ajax.BeginForm need to put another empty begin.form, but depending on the way place or father sends "nulls" information or the first Ajax.BeginForm send a submit to the Ajax.BeginForm "father".
my code :
#using (var f = Html.Bootstrap().Begin(new Form("","").Id("").HtmlAttributes(new { ReturnUrl = Request.QueryString["ReturnUrl"] })))
{
using (Ajax.BeginForm("", "", new AjaxOptions { }))
{
}
using (#Ajax.BeginForm("SaveChanges", "Requests", null, new AjaxOptions { HttpMethod = "POST" }, null))
{
using (Ajax.BeginForm("", "", new AjaxOptions { }))
{
}
using (#Ajax.BeginForm("AddMoney","Requests", null, new AjaxOptions { HttpMethod = "POST" }, null))
{
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="box-title">
<h3>
<i class="fa fa-bars"></i>Money</h3>
<div class="box-tool">
<label class="control-label">
</label>
<a data-action="collapse" href="#"><i class="fa fa-chevron-up"></i></a>
</div>
</div>
<div class="box-content">
<div class="row">
<div class="col-md-3">
<div class="form-group">
#f.FormGroup().TextBoxFor(_ => _.Money).Class("form-control").HtmlAttributes(new { mask = "999999999999" })
</div>
</div>
</div>
</div>
</div>
</div>
</div>
}
using (#Ajax.BeginForm("AddDate", "Request", null, new AjaxOptions { HttpMethod = "POST"}, null))
{
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="row">
<div class="col-md-2" id="divDtFinalCorrecao" style="display: none;">
<div class="form-group">
#f.FormGroup().TextBoxFor(_ => _.date).Class("datepicker"))
</div>
</div>
</div>
</div>
</div>
</div>
}

How to pass an object using the Ajax.BeginForm() helper

I am trying to use the Ajax.BeginForm to post a message back to the server and I need to give a name to the form, i.e. use the parameter htmlAttributes. For that I am using the following signature:
#using (Ajax.BeginForm("SendEmail", "Contacts", null, new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "sendMessageArea" }, new { Name = "sendEmail" }))
This code doestn't work, it updates the whole page and the controller is expecting an object as a paramenter:
public ActionResult SendEmail(Contacts contacts)
Here is the view:
<div class="row">
<div class="large-12 columns" >
#using (Ajax.BeginForm("SendEmail", "Contacts", null, new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "sendMessageArea" }, new { Name = "sendEmail" }))
{
<fieldset class="form-group">
<legend>Leave a message</legend>
<div class="panel">
<div class="row">
<div class="large-offset-2 large-8 columns">
<div class="row">
<div class="large-2 columns">
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label" })
</div>
</div>
<div class="large-8 columns">
#Html.TextBox("Name", Model.Name, new { placeholder = "Your name..." })
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="large-2 columns">
</div>
</div>
<div class="row">
<div class="large-2 columns">
<div class="form-group">
#Html.LabelFor(model => model.EMail, new { #class = "control-label" })
</div>
</div>
<div class="large-8 columns">
<div class="form-group">
#Html.TextBox("EMail", Model.EMail, new { placeholder = "Your email..." })
#Html.ValidationMessageFor(model => model.EMail)
</div>
</div>
<div class="large-2 columns">
</div>
</div>
<div class="row">
<div class="large-2 columns">
<div class="form-group">
#Html.LabelFor(model => model.Message, new { #class = "control-label" })
</div>
</div>
<div class="large-8 columns">
#Html.TextArea("Message", Model.Message, new { placeholder = "Your message here...", #class = "comment-control", id = "message" })
#Html.ValidationMessageFor(model => model.Message)
</div>
<div class="large-2 columns">
</div>
</div>
<div class="row">
<div class="large-offset-8 large-3 columns">
<input type='submit' style='position:absolute;top:0;left:-9999px;width:1px;height:1px' />
<a class='submit-button' href="javascript:sendEmail.submit()">
<span class='submit-button-inner'>Submit</span>
</a>
</div>
</div>
</div>
<div class="large-2 columns">
</div>
</div>
</div>
</fieldset>
}
</div>
and the partial view:
<span class="success label">#Resources.Contacts.Index.SuccessSendMessage</span>
I think the problem should be related with the routeValues parameter because if I use a simple example without the htmlAttributes and routeValues it works well.
Any guess?

Validate Modal Form

I am trying to popup a form so user fill it then I save that record. If data is wrong I want to inform the user just a classic validation issue.
I am trying this code but when model is not valid it show the mistake but literally it only returns what is in the partial view, it is not loading my layout nor my modal form, all I get is a white page just with my partial.
so what am I doing wrong?
This is my modal form:
And after validation all I get is this:
Code:
Model:
public class Car
{
public int Id { get; set; }
[Required]
[StringLength(50, MinimumLength = 6)]
public string Model { get; set; }
public string Brand { get; set; }
public string Year { get; set; }
public string Color { get; set; }
}
View:
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Add Car</h4>
</div>
<div class="modal-body">
#Html.Partial("CreatePartialView",new Car())
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="savechanges">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
my partial:
#model ControliBootstrap.Models.Car
#using (Ajax.BeginForm("ModalAdd", "Cars",new AjaxOptions()
{
UpdateTargetId = "mymodalform"
}))
{
<div class="form-horizontal" id="mymodalform">
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Model, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Model)
#Html.ValidationMessageFor(model => model.Model)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Brand, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Brand)
#Html.ValidationMessageFor(model => model.Brand)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Year, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Year)
#Html.ValidationMessageFor(model => model.Year)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Color, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Color)
#Html.ValidationMessageFor(model => model.Color)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
and finlly my controler:
public ActionResult ModalAdd(Car car)
{
if (ModelState.IsValid)
{
db.Cars.Add(car);
db.SaveChanges();
return RedirectToAction("Index");
}
return PartialView("CreatePartialView",car);
}
Don't forget to include jQuery Unobtrusive AJAX - it's the library that makes normal HTML forms have some AJAX capabilities.

Resources