MVC 4使用局部视图进行验证

时间:2013-04-16 08:07:05

标签: c# jquery ajax asp.net-mvc partial-views

我正在使用MVC 4和Entity Framework来开发一个Web应用程序。我正在使用加载了javascript的部分视图。其中之一是包含验证的创建视图。这就是我的问题:验证。我有一个自定义验证逻辑,例如,如果用户在某个字段(例如“名称”)中输入了某些数字,则会显示错误。

在这里,使用部分视图,它会将我的部分视图重定向到显示的错误,但我想要做的是留在我的主视图(索引视图)并保留显示错误的部分视图。

编辑:

以下是我的部分观点:

@model BuSIMaterial.Models.Person

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Person</legend>

        <div class="editor-label">
            First name : 
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.FirstName, new { maxlength = 50 })
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>

        <div class="editor-label">
            Last name : 
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.LastName, new { maxlength = 50 })
            @Html.ValidationMessageFor(model => model.LastName)
        </div>

        <div class="editor-label">
            National number : 
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.NumNat, new { maxlength = 11 })
            @Html.ValidationMessageFor(model => model.NumNat)
        </div>

        <div class="editor-label">
            Start date : 
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.StartDate, new {@class = "datepicker", @placeholder="yyyy/mm/dd"})
            @Html.ValidationMessageFor(model => model.StartDate)
        </div>

        <div class="editor-label">
            End date : 
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.EndDate, new { @class = "datepicker", @placeholder = "yyyy/mm/dd" })
            @Html.ValidationMessageFor(model => model.EndDate)
        </div>

        <div class="editor-label">
            Distance House - Work (km) : 
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.HouseToWorkKilometers)
            @Html.ValidationMessageFor(model => model.HouseToWorkKilometers)
        </div>

        <div class="editor-label">
            Category : 
        </div>
        <div class="editor-field">
            @Html.DropDownList("Id_ProductPackageCategory", "Choose one ...")
            @Html.ValidationMessageFor(model => model.Id_ProductPackageCategory) <a href = "../ProductPackageCategory/Create">Add a new category?</a>
        </div>

        <div class="editor-label">
            Upgrade? : 
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Upgrade)
            @Html.ValidationMessageFor(model => model.Upgrade)
        </div>

        <br />

        <div class="form-actions">
          <button type="submit" class="btn btn-primary">Create</button>
        </div>
    </fieldset>
}


@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    @Scripts.Render("~/bundles/jqueryui")
    @Styles.Render("~/Content/themes/base/css")
}

在我看来,我有这个:

<div class="form-actions"><button type="button" id="create" class="btn btn-primary">Create</button> </div>
<div id ="create_person"></div>

我加载部分视图的方式:

            $("#create").click(function () {
                var form = $("#create_person").closest("form");
                form.removeData('validator');
                form.removeData('unobtrusiveValidation');
                $.validator.unobtrusive.parse(form);

                $.ajax({
                    url: "/Person/CreateOrUpdate",
                    type: "POST",
                    data: $("#create_person").serialize(),
                    cache: false
                });

//                var url = '/Person/CreatePerson';
//                $("#create_person").load(url);

            });

行动:

[HttpGet]
        public ActionResult CreateOrUpdate()
        {
            ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name");
            return View();
        }


        [HttpPost]
        public JsonResult CreateOrUpdate(Person person)
        {
            ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name", person.Id_ProductPackageCategory);

            try
            {
                if (!ModelState.IsValid)
                {
                    string messages = string.Join("; ", ModelState.Values
                                        .SelectMany(x => x.Errors)
                                        .Select(x => x.ErrorMessage));
                    throw new Exception("Please correct the following errors: " + Environment.NewLine + messages);
                }

                db.Persons.AddObject(person);
                db.SaveChanges();

                return Json(new { Result = "OK" });
            }
            catch (Exception ex)
            {
                return Json(new { Result = "ERROR", Message = ex.Message });
            }
        }

3 个答案:

答案 0 :(得分:2)

如果您发布页面,它将不会返回到动态加载的局部视图。尝试对/ Person / CreatePerson进行ajax调用。您的CreatePerson看起来类似于

[HttpPost]
    public JsonResult CreatePerson(Person person)
    {
        ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name", person.Id_ProductPackageCategory);

    try
    {
        if (!ModelState.IsValid)
        {
            string messages = string.Join("; ", ModelState.Values
                                .SelectMany(x => x.Errors)
                                .Select(x => x.ErrorMessage));
            throw new Exception("Please correct the following errors: " + Environment.NewLine + messages);
        }

        db.Persons.AddObject(person);
        db.SaveChanges();

        return Json(new { Result = "OK" });
    }
    catch (Exception ex)
    {
        return Json(new { Result = "ERROR", Message = ex.Message });
    }
}                                                                                                    `
  

对/ Person / CreatePerson的ajax调用类似于

`

$.ajax({
                url: '/Person/CreatePerson',
                type: "POST",
                data: $("#form").serialize(),
                success: function (responce) {
                    alert(responce.Message);
                },
                error: function (xhr, textStatus) {
                    alert(xhr.status + " " + xhr.statusText);
                }
            });

除了不显眼的验证,动态内容也无法轻松完成。检查链接unobtrusive validation on dynamically added partial view (not working)

答案 1 :(得分:2)

我遇到了这种情况,我的主View使用Ajax帖子来检索PartialViews并将PartialView的标记传递到我的View中。我使用jQuery验证框架来实现客户端不显眼的验证。 当我尝试验证通过Ajax调用加载到页面中的表单时,验证似乎没有起作用,我的表单只是发布了。事实证明,不显眼的jQuery验证器库在完成页面上所有验证规则的加载后解析页面的标记。结果是,jQuery不知道动态添加的标记有任何验证规则,导致在帖子上没有抛出验证错误。

<强>解决方案

Traffy有一种方法可以在不引人注目的jQuery库中公开访问,你可以调用它,这会强制解析器扫描你刚刚加载的标记。为此,您需要将以下代码添加到PartialView(或其他动态加载的内容)

//this code goes in your partial view
$(function(){ 
  //allow the validation framework to re-prase the DOM
  jQuery.validator.unobtrusive.parse(); 

  //or to give the parser some context, supply it with a selector
  //jQuery validator will parse all child elements (deep) starting
  //from the selector element supplied
  jQuery.validator.unobtrusive.parse("#formId");
});

然后在您的父页面中,您可以处理表单提交并检查表单是否有效;

//then in your parent page handle the form submission
$(function(){
  $("#SubmitButton").click(function(){ 
    if (!$("#Form1").valid()){ 
      return false; 
    } 
  });
});

就是这样!! (信用:戴夫的编码)

答案 2 :(得分:0)

我为此开发了一个不错的解决方法。部分页面不会在回发时显示服务器错误。首先,我们得到错误,将它们发送回页面,然后在javascript&amp;重新验证页面。希望,嘿presto!

在您的控制器中:

        if (ModelState.IsValid)
        {
            //... whatever code you need in here
        }            
        var list = ModelStateHelper.AllErrors(ModelState);
        TempData["shepherdErrors"] = list;

我把它放在TempData中,因此可以从部分中轻松检索。是的,我称之为shepherdErrors,这是我的想法所以我可以把这个概念称为我想要的愚蠢名字!将错误代码应用到它们应该存在的位置或者是一般的想法。

在辅助类中:

public class ModelStateHelper
{
    public static IEnumerable<KeyValuePair<string, string>> 
         AllErrors(ModelStateDictionary modelState)
    {
        var result = new List<KeyValuePair<string, string>>();
        var erroneousFields = modelState.Where(ms => ms.Value.Errors.Any())
                                        .Select(x => new { x.Key, x.Value.Errors });

        foreach (var erroneousField in erroneousFields)
        {
            var fieldKey = erroneousField.Key;
            var fieldErrors = erroneousField.Errors
                               .Select(error => new KeyValuePair<string, string>(fieldKey, error.ErrorMessage)); //Error(fieldKey, error.ErrorMessage));
            result.AddRange(fieldErrors);
        }

        return result;
    }
}

然后在加载jquery后的某个地方的html页面上:

function displayShepherdErrors() {
    var shepherdErrors = JSON.parse('@(Newtonsoft.Json.JsonConvert.SerializeObject(TempData["shepherdErrors"]))'.replace(/&quot;/g, '"'));
    var frm;
    var isShepherdErrors = (shepherdErrors && shepherdErrors.length > 0);
    if (isShepherdErrors) {
        errObj = {};
        for (var i = 0; i < shepherdErrors.length; i++) {
            var errorKey = shepherdErrors[i].Key;   //also the id of the field
            var errorMsg = shepherdErrors[i].Value;
            var reg = new RegExp('^' + errorKey + '$', 'gi');
            //find the selector - we use filter so we can find it case insensitive
            var control = $('input').filter(function () {
                if ($(this).attr('id'))
                    return $(this).attr('id').match(reg);
            });

            if (control && control.length) {
                control = control[0];
                var controlId = $(control).attr('name');
                errObj[controlId] = errorMsg;

                //get the containing form of the first input element
                if (!frm)
                    frm = control.form;
            }
        }
        var validator = $(frm).validate();
        validator.showErrors(errObj);
    }
    return isShepherdErrors;
}

var isShepherdErrors = displayShepherdErrors();

这应该是开箱即用的,一般的MVC开发提供的文本框是基于变量名称生成的 - 这是MVC的默认行为。