0

I am trying to have an 'Add New' link which opens a modal window containing an AJAX form, which posts to the server and updates my table with the new data.

From another question I have managed to get my form (which is contained in a partial view) to open in a jQuery dialogue and submit successfully. However if the model is not valid, I can not figure how out how to show the validation errors back to the user.

My controller:

    public ActionResult AddItemOptionForm()
    {
        return PartialView("_AddItemOption");
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult CreateItemOption(ItemDetailItemOptionViewModel model)
    {
        model.ItemId = 1;
        if (ModelState.IsValid)
        {
           //.....
           //Code here to save to the DB - this bit works as expected
           //.....

           return PartialView("_ItemOptionList", itemdetailviewmodel);

        }

        return View(model);
    }

_AddItemOption partial view:

@model shopServer1.Models.ViewModels.ItemDetailItemOptionViewModel

@using (Ajax.BeginForm("CreateItemOption", "Item", 
    new AjaxOptions
    {
        InsertionMode=InsertionMode.Replace,
        UpdateTargetId="item-options-list",
        HttpMethod="POST",
        OnFailure = "handleError",
    }))
    {

@Html.AntiForgeryToken()
@Html.ValidationSummary(true)

<fieldset>

    <div class="editor-label">
        @Html.LabelFor(model => model.ItemOptionId)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.ItemOptionId)
        @Html.ValidationMessageFor(model => model.ItemOptionId)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.ItemOptionCode)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.ItemOptionCode)
        @Html.ValidationMessageFor(model => model.ItemOptionCode)
    </div>

    //....

    <input type="submit" value="Create" />

</fieldset>
}

And finally the javascript I use to show the dialogue:

<script type="text/javascript">
    $(document).ready(function () {
        $('#addItemOption').click(function () {
            var url = $('#itemOptionModal').data('url');

            $.get(url, function (data) {
                $('#itemOptionFormContainer').html(data);

                $('#itemOptionModal').modal('show');
            });
        });
    });

I guess my question is two fold. Firstly am I approaching this in the correct manner? It seems a little overcomplicated to just display a partial view in a popup and handle the form post. And if this is a good approach how do I go about handling the validation? I've tried passing the itemdetailviewmodel back to the partial view but that doesn't seem to do the trick.

Community
  • 1
  • 1
Joseph
  • 2,706
  • 6
  • 42
  • 80

1 Answers1

0

Firstly am I approaching this in the correct manner?

Yes, you were almost there.

It seems a little overcomplicated to just display a partial view in a popup and handle the form post.

Seriously?

And if this is a good approach how do I go about handling the validation?

Since you are invoking the CreateItemOption controller action using an AJAX there are 2 possible outcomes from the execution of this action:

  1. The model is valid => do your database stuff (you said this works fine so I ain't gonna cover it in my answer) and return some JSON object indicating the success of the operation so that you could close the modal and tell the user everything is fine
  2. The model is not valid => redisplay the same partial view containing the form so that the validation errors are shown to the user and he is given a chance to correct them and resubmit the form.

Great, now let's get to it:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateItemOption(ItemDetailItemOptionViewModel model)
{
    model.ItemId = 1;
    if (ModelState.IsValid)
    {
       //.....
       //Code here to save to the DB - this bit works as expected
       //.....

       // everything went fine so we could return a JSON result to the calling AJAX
       return Json(new { success = true });
    }

    // Some validation error occurred => we need to redisplay the same partial
    return PartialView("_ItemOptionList", model);
}

Alright, we have covered the 2 cases described previously. Now let's move to the client side part. We need to modify the Ajax.BeginForm helper and subscribe to the OnSuccess callback so that we are capable of handling the 2 cases I described earlier in my answer:

@using (Ajax.BeginForm("CreateItemOption", "Item", 
    new AjaxOptions
    {
        OnSuccess = "handleSuccess"
        HttpMethod = "POST",
    }))
{
    ..
}

Great, and the final piece of this puzzle is obviously the handleSuccess javascript function that you could host in an external .js file:

var handleSuccess = function(result) {
    if (result.success) {
        // The controller action returned a JSON result => everything went fine at the database level
        // so here we could go ahead and close the modal dialog

        alert('Thanks for submitting the form. Your request has been successfully processed'); // well, you could do something more fancy than an alert here, but my designer's skills are pretty much limited to an alert

        // hide the modal
        $('#itemOptionModal').modal('hide');
    } else {
        // some validation error occurred => we need to redisplay the form and show the validation
        // error
        $('#item-options-list').html(result);
    }
};
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thanks for the informative answer, however I am still having the same problem. I get the alert when successful, however nothing happens when the model is not valid. I've popped on a breakpoint I can see see that the following is getting called: `PartialView("_ItemOptionList", model);` however nothing changes on the view. Perhaps I have an issue with the validation messages but these show in other forms which aren't AJAX so I assumed it was something related to that?! – Joseph Dec 31 '13 at 15:10
  • I hope that the `_ItemOptionList` partial contains the Ajax form does it? Inspect the exact response sent by the server in the `Network` tab of FireBug. Also I hope you've got only one element with `id="item-options-list"` in your DOM. Because that's what the following line will do: `$('#item-options-list').html(result);` => it will attempt to inject the partial refreshing this element. – Darin Dimitrov Dec 31 '13 at 15:11
  • I was passing the wrong object type back to the partial view. FireBug identified this very quickly, so thanks for pointing me that way! All working now :) – Joseph Dec 31 '13 at 15:22