0

I am trying to send and validate a form via jquery ajax. I would like to know if it is possible and how to achieve this.

What do I have?

View:

    @using (Html.BeginForm("Index", "Home"))
    {
        <section id="result">
            @Html.ValidationSummary(false)
        </section>

        <section>
            @Html.LabelFor(model => model.Isbn)
            @Html.TextBoxFor(model => model.Isbn)
            @Html.ValidationMessageFor(model => model.Isbn)
        </section>
        <section>
            @Html.LabelFor(model => model.BookNumber)
            @Html.TextBoxFor(model => model.BookNumber)
            @Html.ValidationMessageFor(model => model.BookNumber)
        </section>
        <section>
            @Html.LabelFor(model => model.Title)
            @Html.TextBoxFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </section>
        <section>
            @Html.LabelFor(model => model.ReleaseDate)
            @Html.TextBoxFor(model => model.ReleaseDate)
            @Html.ValidationMessageFor(model => model.ReleaseDate)
        </section>

        <button type="submit">Go</button>
    }

My javascript:

    <script>
            $(function () {
                    $('form').submit(function () {
                            if ($(this).valid()) {
                                    $.ajax({
                                            url: this.action,
                                            type: this.method,
                                            data: $(this).serialize()
                                    })
                                    .success(function (result) {
                                            $('#result').html(result);
                                    })
                                    .error(function () {
                                            alert("oops! some critical stuff");
                                    });
                            }

                            return false;
                    });
            });
    </script>

At last, my controller:

    [HttpPost]
    public ActionResult Index(Book model)
    {
        if (!ModelState.IsValid)
            return View(model);

        if (model.Title.IsEmpty())
        {
            ModelState.AddModelError("Title", "What are you doing?? The title can't be emtpy!");
            return View(model);
        }

        return View();
    }

So, this is just a case study. I wanted to have the DataAnnotations working on the client side, which already are. And when I post the form to the server, perform some more validations via ModelState.IsValid and ModelState.AddModelError and have this shown back to the client.

Is it possible to accomplish this?

2
  • It is possible. So what is the problem that you are facing? Commented Mar 23, 2014 at 16:11
  • When I submit the form I end up with two copies of the view. Possibly because of the target id to be updated. I would like to know which is the best way to do something like this. Try to stick with the ModelState validations or to return the errors on a JSON. Commented Mar 23, 2014 at 16:41

1 Answer 1

1

Think about what you are doing:

  1. You submit the form to your controller via Ajax
  2. You then return the entire View from the controller (along with any Layouts), and insert it into #result. You now have two copies of the view.

To fix this - make use of a partial view.

i.e. Create a new partial _FormPartial.chstml and place your form contents in it.

@Html.ValidationSummary(false)
    <section>
        @Html.LabelFor(model => model.Isbn)
        @Html.TextBoxFor(model => model.Isbn)
        @Html.ValidationMessageFor(model => model.Isbn)
    </section>
    <section>
        @Html.LabelFor(model => model.BookNumber)
        @Html.TextBoxFor(model => model.BookNumber)
        @Html.ValidationMessageFor(model => model.BookNumber)
    </section>
    <section>
        @Html.LabelFor(model => model.Title)
        @Html.TextBoxFor(model => model.Title)
        @Html.ValidationMessageFor(model => model.Title)
    </section>
    <section>
        @Html.LabelFor(model => model.ReleaseDate)
        @Html.TextBoxFor(model => model.ReleaseDate)
        @Html.ValidationMessageFor(model => model.ReleaseDate)
    </section>

    <button type="submit">Go</button>

Then change your view to use this partial view:

@using (Html.BeginForm("Index", "Home"))
{
    <section id="result">
        @Html.Partial("_FormPartial") 
    </section>       
}

And finally, update the return type of your controller to use PartialView instead of View.

[HttpPost]
public ActionResult Index(Book model)
{
    if (!ModelState.IsValid)
        return PartialView("_FormPartial", model);

    if (model.Title.IsEmpty())
    {
        ModelState.AddModelError("Title", "What are you doing?? The title can't be emtpy!");
        return PartialView("_FormPartial", model);
    }

    return View();
}

Alternatively, look at using Ajax.BeginForm which does the heavy lifting for you.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.