User987
User987

Reputation: 3823

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

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..

Upvotes: 1

Views: 1590

Answers (4)

T. Jung
T. Jung

Reputation: 3657

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.

Upvotes: 0

Pete
Pete

Reputation: 58462

I would do the following:

  1. Make sure your script bundle includes the following 2 files after your jquery and in this order:

    • jquery.validate.js
    • jquery.validate.unobtrusive.js
  2. 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>
  1. 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
   }
}
  1. 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; }
}
  1. 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!
      }
    });
  }
})

Upvotes: 3

The_Outsider
The_Outsider

Reputation: 1925

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.

Upvotes: 3

Krazy_Tech
Krazy_Tech

Reputation: 326

You should stringify the JavaScript Object in the Jquery post

JSON.stringify(data)

Upvotes: 0

Related Questions