Javascript object binding in .NET MVC 5 and server side validation - javascript

I have a class in my project which looks like this:
public class MyClass
{
[Required]
public string keyword { get; set; }
public string saleRange { get; set; }
}
This is how the action looks like:
[HttpPost]
[ActionName("Analyze")]
public ActionResult Analyze(MyClass obj)
{
if (!ModelState.IsValid)
{
return Json("error");
}
else
{
return Json("ok");
}
}
And in jQuery:
$(document).on("click",".btnAnalyze",function() {
var data =
{
keyword: $(".keywordInput").val(),
saleRange: "1"
};
console.log($(".keywordInput").val());
$.post("/Controller/Analyze",data).done(function(){
if (data == "error") {
alert("all fields are required");
}
});
});
As you can see I'm mapping a JS object to a C# class object which I pass to my action. Now what the problem here is, even if I don't supply anything for the keyword property (ie. it's null or ""), the ModelState still shows it's property IsValid as true, but it should be set on false if I don't pass anything as keyword parameter.
This is first part of the problem, the other question I have here is how would I, If I have 10 textbox field, of which all are required. And if user enters only 1/10 of those, I would like to send a message for the first next field user has to validate in order to proceed, like "texbox #2 is required, please enter something" instead of a just general message like "all fields are required" or something like that ?
Can someone help me out with this ?
Why does the modelstate shows the it's valid even though after I dont' supply keyword parameter in the object?
#T.Jung here Is a sample of input:
<input placeholder="Enter keywords" class="form-control keywordInput" type="text" style="width:80%">
It's basically just a plain input field in html..

You can use form validation, which will perform data annotation validation on the client side and you do not have to go to the server side.
$('#btnAnalyze').on('click', function (evt) {
if ($('#YourformId').valid()) {
//Perform AJAX call
}
This way if any of the validations do not work, the form.valid() will throw the data annotation errors. So you can add Required to those fields in the models and it will ensure data is not sent if validation fails.

I would do the following:
Make sure your script bundle includes the following 2 files after your jquery and in this order:
jquery.validate.js
jquery.validate.unobtrusive.js
Create your partial / view for your form:
#model MyClassObject
<form action="/action" method="post" id="form">
<div class="row">
#Html.ValidationMessageFor(m => m.Param1)
#Html.LabelFor(m => m.Param1, new { #class = "label" })
#Html.TextBoxFor(m => m.Param1, new { #class = "textbox" })
</div>
<div class="row">
#Html.ValidationMessageFor(m => m.Param2)
#Html.LabelFor(m => m.Param2, new { #class = "label" })
#Html.TextBoxFor(m => m.Param2, new { #class = "textbox" })
</div>
<div class="row">
#Html.ValidationMessageFor(m => m.Param3)
#Html.LabelFor(m => m.Param3, new { #class = "label" })
#Html.TextBoxFor(m => m.Param3, new { #class = "textbox" })
</div>
<input type="submit" value="submit">
</form>
Do you server side validation
[HttpPost]
[ActionName("action")]
public ActionResult action(MyClassObject obj)
{
if(!ModelState.IsValid)
{
return action(); // this is your original action before you do the post
}
else
{
// do your processing and return view or redirect
return View(); // or redirect to a success page
}
}
Add the error message to your class:
public class MyClassObject
{
[Required(ErrorMessage = "Please enter a keyword")]
public string keyword { get; set; }
public string saleRange { get; set; }
}
Your js validation will be plumbed in now but you will need to stop the form from posting and check the validation before doing your ajax request:
var form = document.getElementById('form'), // get a normal js form (I do this just so I can pass in the method and action dynamically - seems better than using .attr() to get them
jqForm = $(form);
jqForm.on('submit', function(e) {
e.preventDefault();
if (jqForm.valid()) {
var formData = jqForm.serializeArray(); // I use serializeArray so I can add extra values if I need to, you can use serialize()
// formData.push({ name: this.name, value: this.value }); - optional for adding extra data
$.ajax({
url: form.action, // this can be just a specific json url if you just need to get some json - it doesn't have to be the same url as the fallback (no js url)
type: form.method,
data: formData,
success: function(result) {
// do success stuff!
}
});
}
})

You should stringify the JavaScript Object in the Jquery post
JSON.stringify(data)

If you want to do the Validation on server side:
Contoller:
[HttpPost]
[ActionName("Analyze")]
public ActionResult Analyze(Model viewModel)
{
if(viewModel.PropertyName.IsNullOrEmpty()){
{
ModelState.AddModelError("PropertyName", "The Field InputFieldName neeeds to be filled!");
}
if (ModelState.IsValid)
{
//Do what ever you want with your Inofrmation
//return a redirct or anything else
}
//If you got here some fields are not filled
return View(viewModel);
}
View:
#Html.TextBoxFor(x => x.PropertyName)
#Html.ValidationMessageFor(m => m.PropertyName, "", new { #class = "text-danger" })
//#class = "text-danger" only if you're using bootstrap
I do all of my validation this way.

Related

ajax mvc html: jquery val not preventing call to api

When clicking a button I am calling a web api with ajax. My form is using JqueryVal, to make form validations, according to my viewmodel data annotations.
My problem is that when I click the button "Listo" in my form, it calls my API, inspite of jqueryval is marking an error( selecting a file is required)
This is my code:
My viewmodel that contains data annotations(the dataannotations are used along with the jquery.validate.js and jquery.validate.unobtrusive.js. As you can see, it is working, but is not preventing the API from being called):
public class CursoViewModel
{
public Guid Id { get; set; }
[MaxLength(125)]
public string Titulo { get; set; }
[Required]
public string Descripcion { get; set; }
[Required(ErrorMessage ="selecciona una imagen para tu curso")]
[DataType(DataType.Upload)]
public HttpPostedFileBase Imagen { get; set; }
}
The class posted to my api
public class person
{
public string name { get; set; }
public string surname { get; set; }
}
The Api code
[HttpPut]
[Route("api/ProfesorCurso/test")]
public string Put(person p)
{
return p.name + p.surname;
}
My View
#model project.ViewModels.CourseViewModel
<form id="Editcurso" method="post" action="#">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "Please fix the following errors.")
<div class="container">
<div class="form-group">
#Html.LabelFor(c=>c.Titulo)
#Html.TextBoxFor(c => c.Titulo, new {id="titulo", #class="form-control"})
#Html.ValidationMessageFor(m => m.Titulo)
</div>
<div class="form-group">
#Html.LabelFor(c => c.Descripcion)
#Html.TextAreaFor(c => c.Descripcion, new {id="descripcion", #class = "form-control" })
#Html.ValidationMessageFor(m => m.Descripcion)
</div>
<div class="thumbnail" id="imagencurso"></div>
<div class="form-group">
#Html.LabelFor(m => m.Imagen)
#Html.TextBoxFor(m => m.Imagen, new {id="imagen" ,type = "file", data_rule_validCustomer = "true" })
#Html.ValidationMessageFor(m => m.Imagen)
</div>
<button id="submiter" type="submit" class="btn btn-primary">Listo!</button>
</div>
</form>
The scripts in the view
#section scripts
{
#Scripts.Render("~/bundles/jqueryval")
<script>
$(document).ready(function () {
$("#submiter").click(function () {
jQuery.support.cors = true;
var person = new Object();
person.name = "Sourav";
person.surname = "Kayal";
$.ajax({
url: '/api/ProfesorCurso/test',
type: 'PUT',
dataType: 'json',
data: person,
success: function (data) {
console.log(data);
return false;
},
error: function (x, y, z) {
alert('error al postear');
return false;
}
});
});
});
</script>
}
What can I do to prevent ajax to call my api when clicking my form button, if there are Jquery validation errors?
thanks
You should be handling the .submit() event of the form, and then your can check .valid(), and if not cancel the ajax call. Note you should also be cancelling the default submit.
$('#Editcurso').submit(e) {
e.preventDefault(); // prevent the default submit
if (!$(this).valid()) {
return; // exit the function and display the errors
}
....
$.ajax({
....
});
}
As a side note, there is no point adding new { id="titulo" } etc - the HtmlHelper methods that generate form controls already add an id attribute based on the property name

Validation fires but doesn't show message on failure. What am I missing? MVC 5 Razor

I can't seem to get the Validation error messages to show under the input model fields on the View.
The [Required] tag above Description input makes the ModelState Invalid, but doesn't stop the submission. I have to catch it with checking the Model State. Am I missing some .js files? I dont' have any examples to doublecheck this.
Here is my model (notice I have only one [Required] for now):
public partial class Requests
{
public int RequestID { get; set; }
public string NickName { get; set; }
public Nullable<double> Lat { get; set; }
public Nullable<double> Lng { get; set; }
public string ZipCode { get; set; }
[Required(ErrorMessage = "Description of what you need is missing.")]
public string Description { get; set; }
public System.DateTime DateCreated { get; set; }
}
Here is my View where the Description input needs input.
<div class="form-group">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.Description, new { htmlAttributes = new { #class = "form-control", #rows = "20", #cols = "200" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
Here is my controller ActionResult (skinnied down)
if (ModelState.IsValid)
{
//THIS ALL WORKS IF Description HAS INPUT
}
else
{
TempData["Saved"] = "Nothing saved yet. Look for reason.";
return RedirectToAction("StoreRequests", new { lat = requests.Lat, lng = requests.Lng });
}
On ModelState failure the user is directed to the correct View and TempData shows that nothing was saved. However, there is no error message on the View below the offending input, no ValidationSummary at the top of the view, and submission is not stopped on input mistake.
#if(TempData["Saved"] != null)
{
<span style="color: red;">#TempData["Saved"].ToString()</span>
}
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
In order to get client side validation (and therefore prevent the form being submitted if its invalid), you need to include the following scripts in you view (or layout).
jquery-{version}.js
jquery.validate.js
jquer.validate.unobtrusive.js
If you have the default bundles set up by VS when you create a new project, you can simply add the following to the view
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
In addition, you should not be redirecting if ModelState is invalid, but rather returning the current view, which will display any validation errors even if the user has disabled javascript. By redirecting, your lose current ModelState so no validation errors will be displayed in the view your redirecting to, not to mention that any data the user previously filled (except the 2 parameters your passing) will be lost.
public ActionResult Edit (Requests model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// save you data and redirect
}
Include the following necessary scripts directly in your .cshtml file.
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>

How to use Jquery/Ajax with asp.net MVC 4 with partial view and action with model

I am new to both asp.net MVC and JQuery so be gentle.
I am trying to use a HTTP Post to update my contact form, used to send an email, using AJAX. I have seen lots of posts but what I want seems specific and I cant seem to find anything relevant.
The down low: I have a layout page which has the header, renders the body and has my footer in. My footer contains the form I want to submit. I want to submit this form without refreshing the whole page. The layout page:
<div id="footer">
#{Html.RenderAction("Footer", "Basic");}
</div>
<p id="p"></p>
I have a model for this form to send an email.
namespace SimpleMemberShip.Models
{
public class EmailModel
{
[Required, Display(Name = "Your name")]
public string FromName { get; set; }
[Required, Display(Name = "Your email"), EmailAddress]
[StringLength(100, ErrorMessage = "The email address entered is not valid")]
public string FromEmail { get; set; }
[Required]
public string Message { get; set; }
}
The footer:
<h2> footer yo !</h2>
#Html.ValidationSummary()
<fieldset>
<legend>Contact Me!</legend>
<ol>
<li>
#Html.LabelFor(m => m.FromEmail)
#Html.TextBoxFor(m => m.FromEmail)
</li>
<li>
#Html.LabelFor(m => m.FromName)
#Html.TextBoxFor(m => m.FromName)
</li>
<li>
#Html.LabelFor(m => m.Message)
#Html.TextBoxFor(m => m.Message)
</li>
</ol>
<button id="submit"> Submit </button>
</fieldset>
controller:
[ChildActionOnly]
public ActionResult Footer()
{
return PartialView("~/Views/Shared/_Footer.cshtml");
}
[HttpPost]
public ActionResult Footer(EmailModel model)
{
return PartialView("~/Views/Shared/_Footer.cshtml");
}
I want to use the model validation and everything to be the same or similar as if the form was posted normally through the server.
Edit:
My new code, which works great! but it only works once, when the button is clicked again nothing happens. Anyone know why?
<script type="text/javascript">
$("#submit").click(function () {
$("#footer").html();
var url = '#Url.Action("Footer", "Basic")';
$.post(url, { FromName: $("[name=FromName]").val(), FromEmail: $(" [name=FromEmail]").val(), Message: $("[name=Message]").val() }, function (data) {
$("#footer").html(data);
});
var name = $("[name=FromName]").val();
$("#p").text(name);
});
</script>
new Edit:
did some research and using
$("#submit").live("click",function () {
instead of
$("#submit").click(function () {
seemed to do the trick.
<script type="text/javascript">
$("#submit").live("click",function () {
$('.validation-summary-errors').remove();
var url = '#Url.Action("Footer", "Basic")';
$.post(url, { FromName: $("[name=FromName]").val(), FromEmail: $("[name=FromEmail]").val(), Message: $("[name=Message]").val() }, function (data) {
$("#footer").html(data);
});
});
</script>
ended up with this but will try the "serialize()" option next time.
controller was changed to this without the [ChildActionOnly] and works perfect now
[HttpPost]
public ActionResult Footer(EmailModel model)
{
return PartialView("~/Views/Shared/_Footer.cshtml");
}
Thank you everyone that helped!
Change the [ChildActionOnly] to [HttpGet] in the controller
You can pass model data to controller by doing the following steps
1. Get the input values on click of submit and sent to the Footer action in controller
$("#submit").click(function () {
var FromEmailValue = $('#FromEmail').val();
var FromNameValue = $('#FromName').val();
var MessageValue = $('#Message').val();
var url = '#Url.Action("Footer", "Basic")';
$.ajax({
url: urlmodel,
data: { FromName: FromNameValue, FromEmail: FromEmailValue, Message: MessageValue},
cache: false,
type: "POST",
success: function (data) {
do something here
}
error: function (reponse) {
do something here
}
});
});
In the controller
``
[HttpGet]
public ActionResult Footer()
{
return PartialView("~/Views/Shared/_Footer.cshtml");
}
[HttpPost]
public ActionResult Footer(string FromName = "", string FromEmail = "", string Message = "")
{
//for ajax request
if (Request.IsAjaxRequest())
{
do your stuff
}
}

How to popup alert when TextBoxFor's input does not exist in database?

NPG_Chemical_Measurement_Methods is an ICollection type. In my Chemical.cshtml, I have:
<div id="nioshs">
#Html.EditorFor(model => model.NPG_Chemical_Measurement_Methods)
</div>
and in the EditorTemplate view:
<div class="method" style="display:inline-block;">
<p>
#Html.RemoveLink("x", "div.method", "input.mark-for-delete")
#Html.HiddenFor(x => x.DeleteMethod, new { #class = "mark-for-delete" })
#Html.TextBoxFor(x => x.Measurement_Method)
#Html.ValidationMessageFor(model => model.Measurement_Method, "", new { #class = "text-danger" })
#Html.Hidden("Measurement_Type", "NIOSH")
</p>
</div>
I want to have something like when I give input for #Html.TextBoxFor(x => x.Measurement_Method), then click on other place of the current page, an alert will popup says Not exist in Database if record cannot be found in Measurement_Method table.
NPG_Chemical.cs has:
public partial class NPG_Chemical
{
public NPG_Chemical()
{
this.NPG_Chemical_Measurement_Methods = new HashSet<NPG_Chemical_Measurement_Method>();
}
[StringLength(256)]
[Remote("IsUserExists", "NPG_Chemical", ErrorMessage = "Chemical Name already in use")]
public string Chemical { get; set; }
public virtual ICollection<NPG_Chemical_Measurement_Method> NPG_Chemical_Measurement_Methods { get; set; }
internal void CreateMeasurementMethods(int count = 1)
{
for (int i = 0; i < count; i++)
{
NPG_Chemical_Measurement_Methods.Add(new NPG_Chemical_Measurement_Method());
}
}
Measurement_Method.cs has:
public partial class NPG_Chemical_Measurement_Method
{
[StringLength(256)]
[Remote("IsNIOSHExists", "NPG_Chemical", ErrorMessage = "NIOSH number does not exist")]
public string Measurement_Method { get; set; }
}
NPG_ChemicalController has:
public JsonResult IsUserExists(string Chemical)
{
return Json(!db.NPG_Chemical.Any(x => x.Chemical == Chemical), JsonRequestBehavior.AllowGet);
}
public JsonResult IsNIOSHExists(string Measurement_Method)
{
System.Diagnostics.Debug.WriteLine("value:",Measurement_Method);
return Json(db.NPG_NIOSH_Method.Any(x => x.Measurement_Number == Measurement_Method), JsonRequestBehavior.AllowGet);
}
This hopefully will get you close. I'm just writing this from memory. But basically one way to do this is handle an onblur event of your textbox with a javascript function. Then do an ajax call to a controller sending the value of Measurement_Method, validate the data and return true or false. If false show an alert box. You'll need to include the jquery library to use this.
#Html.TextBoxFor(x => x.Measurement_Method, new {onblur = "Validate()"})
Then javascript
function Validate() {
$.ajax({
url: "#Url.Action("CheckTextField", "Controller")\?value=" + $('#Measurement_Method').val(),
dataType: "html",
success: function(data) {
if (data == "false")
{
alert('Not exist in Database');
}); }
Your controller
public string CheckTextField(string value)
{
//validate the value here
return "true" or "false"
}

ASP.net MVC Success Alert After Form submit

I want to display success Alert pop-up or alert message after form submited and action succeded
In this example I want to show "successfully add" :
Create Action :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(TAUX taux)
{
if (ModelState.IsValid)
{
db.TAUX.Add(taux);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CAT_ID = new SelectList(db.CATEGORIE, "CAT_ID", "LIBELLE", taux.CAT_ID);
ViewBag.C_GARANT = new SelectList(db.GARANTIE, "C_GARANT", "LIB_ABREGE", taux.C_GARANT);
return PartialView("_Create", taux);
}
Index Action :
public ActionResult Index()
{
var taux = db.TAUX.Include(t => t.CATEGORIE).Include(t => t.GARANTIE);
return View(taux.ToList());
}
What should I add to do this ?
It's possible, for sure, but implementation details might change from technologies and app structure.
One of the most common ways for doing this (and the one I'm currently using with great success) is to receive whater-you-need-to-receive and return a JSON object with the status and/or error message, which will be used by some script on your view.
For example:
[Route(""), HttpPost]
public JsonResult DoSomethingOnTheServer(DoSomethingViewModel vm)
{
try
{
if (DoSomething(vm)) return Success();
else return Error("The server wasn't able to do something right now.");
}
catch (Exception err)
{
return Error(err.Message);
}
}
public JsonResult Success() { return Json(new { Success = true, Message = "" }); }
public JsonResult Error(string message) { return Json(new { Success = false, Message = message }); }
This way, you can do something like:
<script>
$.ajax({
url: "/",
method: "POST",
data: getMyData(),
success: function(json) {
if (json.Success) {
alert("Wow, everything was fine!");
} else {
alert(json.Message);
}
},
// This will be trigered whenever your ajax call fails (broken ISP link, etc).
error: function() {
alert("Something went wrong. Maybe the server is offline?");
}
});
</script>
Being honest with you, it's possible to submit the form (regular submit, I mean) and on the page refresh, display whatever you want.
This will, however, force you to load something extra with your view model, like an extra <script> tag or some extra <div> tags and to check for that every time.
From a usability/design point-of-view, it's a no-go. Avoid page refresh whenever possible because they give a feeling for the user that the app is either going away or that he/she is now moving outsinde the app.
Also, from a performance point-of-view, "full round-trips" to the server, consisting of sending the form data and retrieving a whole new page (with the whole layout, scripts, razor rendering/parse and all) is a massive problem just to show "success/fail" for the end-user so, again: avoid it whenever possible.
IMHO, returning either a view or a partial view only to display a message to the end-user is just wasting both yours and your end-users' link.
I used to make Ajax Form and in the OnSuccess fucntion i show message :
#using (Ajax.BeginForm("Edit1", "Availability", new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.InsertBefore, UpdateTargetId = "formAddAvailabilityContainer", OnSuccess = "AddAvailabilitySuccess" }, new { #class = "AjaxForm", #id = "formAvailability_" + Model.Id }))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.HiddenFor(model => model.UserId)
#Html.EditorFor(model => model.StartTime)
#Html.MyValidationMessageFor(model => model.StartTime)
#Html.EditorFor(model => model.EndTime)
#Html.MyValidationMessageFor(model => model.EndTime)
#Html.EditorFor(model => model.RecurrenceFreq)
#Html.MyValidationMessageFor(model => model.RecurrenceFreq)
#Html.TextBoxFor(model => model.EndsAfterValue, new {id="txtBoxEndsAfterValue" })
#Html.MyValidationMessageFor(model => model.EndsAfterValue)
#Html.EditorFor(model => model.EndsByDate)
<input type="submit" class="btn btn-primary" value="Save" id="btnsubmit" />
<input type="button" class="btn btn-primary btnCancelAvailability" id="0" value="Cancel">
}
<script>
function AddAvailabilitySuccess()
{
alert("Record updated successfully!");
}
</script>
I have a way to do this, using the ViewBag.
In your controller you must add:
if (ModelState.IsValid)
{
db.TAUX.Add(taux);
db.SaveChanges();
ViewBag.SuccessMsg = "successfully added";
return RedirectToAction("Index");
}
Then in the Index view:
#{
var message = ViewBag.SuccessMsg;
}
<script type="text/javascript">
var message = '#message';
if(message){
alert(message);
}
</script>
in the end you use JavaScript mixed with the MVC ViewBag :)

Categories

Resources