MVC和AJAX与JQuery

I am really confused by looking at so many approaches the way JQuery and AJAX are used with MVC and there is no proper documentation I found.

I have a very common scenario in my applications where I have a Form which is a partial view user will submit which will be stored to database if its valid and if not than show user same form again and show an error on the page.

Whats simplest way to do this ? Can I achieve this using simple AJAXForm or I will have to use JSON and JQuery as well ?

 <script type="text/javascript">

        function successContactList() {
               alert("Success.");
      }

        function failureContactList() {
            alert("Error.");
        }

    </script>


    <% using (Ajax.BeginForm("SaveMailingList", "Contacts", new AjaxOptions { OnFailure = "failureContactList", OnComplete = "successContactList", UpdateTargetId = "ContactArea" })) { %>
    <div id="ContactArea">

        <%: Html.EditorFor(Model => Model)  %>
         <input type="submit" value="Save" />
    </div>
    <% } %>



    [HttpPost]
        public ActionResult SaveMailingList(IEnumerable<ContactsInMailingListsViewModel>  contactInMailing) {
            var mailingList = contactInMailing.FirstOrDefault();
            var contact = repository.GetContactById(mailingList.ContactId);
            repository.UpdateMailingList(contactInMailing,contact);
            contactInMailing.FirstOrDefault().EndDate = new DateTime(2077,1,1);
            return PartialView(contactInMailing);

        }

I see two problems with your question.

  1. Have you researched your terms? jQuery is often used for doing AJAX manipulations, and MVC stands for Model-View-Controller, which is one way for your server side code structuring (separation of view and service code). JSON can be used for data exchange and manipulation (a bit like XML, only simpler), and is not required when you're using forms.
  2. You haven't told us what is your server side technology. Although forms are basic parts of html specification, you still have to handle them somehow on the server side.

The most direct answer to your question is. Yes!

AJAX and MVC are abstract concepts. They really don't mean much outside of an implementation context. For example JQuery implements the concept of AJAX, and Symphony implements the concept of MVC.

What do you need to do? What are your requirements? What kind of user experience do you want?

If you just doing some simple error checking on the form. By all means just do a basic html form post, return built into your MVC implementation.

If you are really using your partial as a partial and doing something like a poll or another embedded form system where reloading the entire page is not acceptable then AJAX is your ticket.

As for what implementations to use. I would look to see what your MVC has built in. If for some reason it does not already provide an ajax system. I personal like JQuery.

I did below and it worked for me in MVC 3.

In my scenario I had 3 forms (3 partial views) on the page and I just wanted them to submit via ajax and update the corresponding partial view.

After updating the form dynamically need to add back submit event handler and also call $.validator.unobtrusive.parse('#Form1); to make client side validation work for next submits.

Used below function to get partial view html in string in the Action method of the controller.

//Renders Partial View as a string
//Parameters: Calling Controller Context, partial view name, model
//Reference:http://stackoverflow.com/questions/3234003/render-view-programmatically-into-a-string
public static string RenderPartialViewToString(ControllerContext context, string viewName, object model)
    {
        if (string.IsNullOrEmpty(viewName))
            viewName = context.RouteData.GetRequiredString("action");

        context.Controller.ViewData.Model = model;

        using (StringWriter sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
            ViewContext viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw);
            // copy model state items to the html helper 
            foreach (var item in viewContext.Controller.ViewData.ModelState)
                if (!viewContext.ViewData.ModelState.Keys.Contains(item.Key))
                {
                    viewContext.ViewData.ModelState.Add(item);
                }

            viewResult.View.Render(viewContext, sw);

            return sw.GetStringBuilder().ToString();
        }
    }

1. Index View -

<script type='text/javascript'>
    $(document).ready(function () {

    //Add Event handlers for the forms after document is ready.
    $("#Form1").submit(Form1SubmitHandler);

    $("#Form2").submit(Form2SubmitHandler);

    $("#Form3").submit(Form3SubmitHandler);
});

//Submit Event handler for Form1Form
function Form1SubmitHandler(event) {
    event.preventDefault();
    if ($("#Form1").valid()) {
        Form1Ajax();
    }
}

//Submit Event handler for Form2 Form
function Form2SubmitHandler(event) {
    event.preventDefault();
    if ($("#Form2").valid()) {
        Form2Ajax();
    }
}

//Submit Event handler for Form3 Form
function Form3SubmitHandler(event) {
    event.preventDefault();
    if ($("#Form3").valid()) {
        Form3Ajax();
    }
}

//Submit Form1
function Form1Ajax() {
    if ($("#Form1").valid())
    {
        $.ajax({
            type: 'POST',
            url: '@Url.Action("Action1", "Controller")',
            cache: false,
            data: { //send your form values here
            },
            dataType: "json",
            success: function (data) {
                if (data.IsSuccess) {

                    //Update the partial view.
                    $("#Form1Partial").html(data.ViewHtml);

                    //Have to call this to make client side validation work after dynamically adding a form.
                    $.validator.unobtrusive.parse('#Form1');

                    //Add event handler for submit.
                    $("#Form1").bind("submit", Form1SubmitHandler);
                }
                else {

                    //Update the partial view.
                    $("#Form1Partial").html(data.ViewHtml);


                    //Have to call this to make client side validation work after dynamically adding a form.
                    $.validator.unobtrusive.parse('#Form1);

                    //Add event handler for submit.
                    $("#Form1").bind("submit", Form1SubmitHandler);
                }
            }
        });
    }
}

//Submit Form2
function Form2Ajax() {
    if ($("#Form2").valid())
    {
        $.ajax({
            type: 'POST',
            url: '@Url.Action("Action2", "Controller")',
            cache: false,
            data: { //send your form values here
            },
            dataType: "json",
            success: function (data) {
                if (data.IsSuccess) {

                    //Update the partial view.
                    $("#Form2Partial").html(data.ViewHtml);

                    //Have to call this to make client side validation work after dynamically adding a form.
                    $.validator.unobtrusive.parse('#Form2');

                    //Add event handler for submit.
                    $("#Form2").bind("submit", Form2SubmitHandler);
                }
                else {

                    //Update the partial view.
                    $("#Form2Partial").html(data.ViewHtml);


                    //Have to call this to make client side validation work after dynamically adding a form.
                    $.validator.unobtrusive.parse('#Form2);

                    //Add event handler for submit.
                    $("#Form2").bind("submit", Form2SubmitHandler);
                }
            }
        });
    }
}

//Submit Form3
function Form3Ajax() {
    if ($("#Form3").valid())
    {
        $.ajax({
            type: 'POST',
            url: '@Url.Action("Action3", "Controller")',
            cache: false,
            data: { //send your form values here
            },
            dataType: "json",
            success: function (data) {
                if (data.IsSuccess) {

                    //Update the partial view.
                    $("#Form3Partial").html(data.ViewHtml);

                    //Have to call this to make client side validation work after dynamically adding a form.
                    $.validator.unobtrusive.parse('#Form3);

                    //Add event handler for submit.
                    $("#Form3").bind("submit", Form3SubmitHandler);
                }
                else {

                    //Update the partial view.
                    $("#Form3Partial").html(data.ViewHtml);


                    //Have to call this to make client side validation work after dynamically adding a form.
                    $.validator.unobtrusive.parse('#Form3);

                    //Add event handler for submit.
                    $("#Form3").bind("submit", Form3SubmitHandler);
                }
            }
        });
    }
}

<div id="Form1Partial">@Html.Partial("Form1Partial", Model.model1)</div>
<div id="Form2Partial">@Html.Partial("Form2Partial", Model.model2)</div>
<div id="Form3Partial">@Html.Partial("Form3Partial", Model.model3)</div>

2. Form1PartialView

@using (Html.BeginForm("Action1", "Controller", FormMethod.Post, new { @id = "Form1" }))
{
    <!-Form elements go here->                    
    <button type='submit'>Submit Form1</button>
}

3. Form2PartialView

@using (Html.BeginForm("Action2", "Controller", FormMethod.Post, new { @id = "Form2" }))
{
   <!-Form elements go here->                    
   <button type='submit'>Submit Form2</button>
}

4. Form3PartialView

@using (Html.BeginForm("Action3", "Controller", FormMethod.Post, new { @id = "Form3" }))
{
    <!-Form elements go here->                    
    <button type='submit'>Submit Form3</button>
}

5. Controller Code

[HttpPost]
public ActionResult Action1(Model model)
{
 if (ModelState.IsValid)
 {
    //Do some thing

    return Json ( new { IsSuccess = true, ViewHtml = RenderPartialViewToString(ControllerContext, "Form1Partial", model) });     

 }

  // If we got this far, something failed,
  return Json ( new { IsSuccess = false, ViewHtml = RenderPartialViewToString(ControllerContext, "Form1Partial", model) });
}

[HttpPost]
public ActionResult Action2(Model model)
{
 if (ModelState.IsValid)
 {
    //Do some thing

    return Json ( new { IsSuccess = true, ViewHtml = RenderPartialViewToString(ControllerContext, "Form2Partial", model) });     

 }

  // If we got this far, something failed,
  return Json ( new { IsSuccess = false, ViewHtml = RenderPartialViewToString(ControllerContext, "Form2Partial", model) });
}

[HttpPost]
public ActionResult Action3(Model model)
{
 if (ModelState.IsValid)
 {
    //Do some thing

    return Json ( new { IsSuccess = true, ViewHtml = RenderPartialViewToString(ControllerContext, "Form3Partial", model) });     

 }

  // If we got this far, something failed,
  return Json ( new { IsSuccess = false, ViewHtml = RenderPartialViewToString(ControllerContext, "Form3Partial", model) });
}