2

I'm currently working on a ASP.NET MVC 4 project as a trainee and I'm trying to implement an admin panel. The goal is to show all the users on a grid (MVC.GRID) and edit them on the same page. I've managed to show all the users on the grid and once a user is selected it shows the info below the grid and puts it in a form (via ajax/jquery).

The problem is: the form validation is being displayed on a new page and not on the page where the grid is at. And I've no idea why..

Below is my code.

This is where the form is placed:

<div id="order-content">
  <p class="muted">
    Select a user to see his or her information
  </p>
</div>

The form itself (partial view "_UserInfo):

@using (Ajax.BeginForm("EditUser", "Admin", FormMethod.Post, 
  new AjaxOptions
  {
    InsertionMode = InsertionMode.Replace,
    HttpMethod = "POST",
    UpdateTargetId = "order-content"
  }))
{
  @Html.Bootstrap().ValidationSummary()
  @Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Id)
  @Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Name)
  @Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Password)
  @Html.Bootstrap().SubmitButton().Text("Opslaan").Style(ButtonStyle.Primary)
}

JQuery to show the user info once a row is selected:

$(function () {
pageGrids.usersGrid.onRowSelect(function (e) {
  $.post("/Admin/GetUser?id=" + e.row.Id, function (data) {
    if (data.Status <= 0) {
      alert(data.Message);
      return;
    }
    $("#order-content").html(data.Content);
  });
});
});

My AdminController:

[HttpPost]
public JsonResult GetUser(int id)
{
  var user = _UserService.Get(id);
  var input = _EditInputMapper.MapToInput(user);
  if (user == null)
    return Json(new { Status = 0, Message = "Not found" });

  return Json(new { Content = RenderPartialViewToString("_UserInfo", input) });
}

[HttpPost]
public ActionResult EditUser(AdminUserEditInput input)
{
  if (ModelState.IsValid)
  {
    // todo: update the user
    return View();
  }
  // This is where it probably goes wrong..
  return PartialView("_UserInfo",input);
}

Can anyone see what is wrong with my code?

Thank you.

Nixxing
  • 23
  • 1
  • 1
  • 5
  • in "order-content", you are showing the "_UserInfo". and this _UserInfo is bind with model data. so the model validation should show up in "order-content". isn't it? Or am I not understanding your question? – Reza.Hoque Oct 01 '13 at 10:35
  • Yes it does. But when I submit empty fields, the page reloads and shows my form with validation but my grid disappears. It seems like mvc creates a new page with only the partial view in it. – Nixxing Oct 01 '13 at 10:56
  • check the ajax submit, you can use Firebug to check...the page should not reload in case of ajax submit – Reza.Hoque Oct 01 '13 at 12:31

2 Answers2

0

When the ModelState is valid and you return View(), does this full view gets embedded in order-content? I suspect not, and if so it would be because the ajax request is not being sent . You may not have included the jquery.unobtrusive-ajax js file

bilal.haider
  • 318
  • 1
  • 4
  • 18
  • No it doesn't, but I haven't implemented it yet. – Nixxing Oct 16 '13 at 14:35
  • To be able to use unobstrusive features you have to include this js file. I would still like to know if you have included the jquery.unobtrusive-ajax.js file. As kandroid has also mentioned the request is not being sent via ajax. Ajax.BeginForm is not working as it should, because the full view you are returning should also be embedded in "order-content" div – bilal.haider Oct 18 '13 at 18:45
0

I've got it working now.. With the use of an jsonvalidator. I don't know if it's a good solution but it does the job for now..

This is what I've changed in my AdminController

[HttpPost]
public ActionResult EditUser(AdminUserEditInput input)
{
  int id = (int)TempData["UserID"];

  if (ModelState.IsValid)
  {
    _UserService.ChangeMail(id, input.Mail);
    _UserService.ChangeName(id, input.Firstname, input.Name);

    return new RedirectResult(Url.Action("Users", "Admin") + "#id=" + id);
  }
  else
  {

    return new JsonResult { Data = new { Valid = false, Errors = Validator.CheckModelErrors(ModelState) } };
  }
}

Added a JsonValidator class:

  public static class Validator // todo: doesn't belong in the controllers directory ?
  {
    public static List<JsonError> CheckModelErrors(System.Web.Mvc.ModelStateDictionary modelstate)
    {
      List<JsonError> errorlist = new List<JsonError>();
      if (modelstate != null && modelstate.Values != null)
      {
        foreach (var m in modelstate.Values)
        {
          if (m.Errors != null)
          {
            foreach (var e in m.Errors)
            {
              errorlist.Add(new JsonError() { ErrorMessage = e.ErrorMessage ?? "" });
            }
          }
        }
      }
      return errorlist;
    }
  }

And a JsonError class..

  public class JsonError // todo: doesn't belong in the controllers directory ?
  {
    public string ErrorMessage { get; set; }
    public bool HasError { get; set; }
    public bool CanPerform { get; set; }
  }

Last but not least, js:

$(document).on('submit', '#UserForm', function (e) {
    e.defaultPrevented();
    $('#UserForm').validate();
    $.post($(this).attr("action"), $(this).serialize(), function (json) {
      if (json.Valid) {
        $("#order-content").html('<p class="muted"> Select a user.</p>');
      }
      else {
        $("#ShowValidation").empty();
        var list = $("#ShowValidation").append('<ul></ul>').find('ul');
        $.each(json.Errors, function (index, optionData) {
          list.append('<li>' + optionData.ErrorMessage + '</li>');
        })
      }
    }, "json");
  });

I was thinking about another way to manage this because this is just temporary.. Should it be a good idea to store the input with the validation messages in a session and let js put it in the _UserInfo view?

Nixxing
  • 23
  • 1
  • 1
  • 5