Kendo Grid Edit InLine Custom Validation message e.g. for duplicate Names etc

假如想象 提交于 2019-12-02 20:57:45

We accomplished this in a Grid just like you did on the controller side by adding our custom error to the model state and passing that back to the view. And then in the onError javascript event we built the validation message ourselves and placed it in the grid.

Javascript onError:

function onError(e, status) {
    if (e.errors) {
        var message = "Error:\n";  

        var grid = $('#gridID').data('kendoGrid');
        var gridElement = grid.editable.element;

        $.each(e.errors, function (key, value) {
             if (value.errors) {
                gridElement.find("[data-valmsg-for=" + key + "],[data-val-msg-for=" + key + "]")
                .replaceWith(validationMessageTmpl({ field: key, message: value.errors[0] }));
                gridElement.find("input[name=" + key + "]").focus()
             }
        });
    }
}

Then create a validationMessageTmpl (or whatever you want to call it):

var validationMessageTmpl = kendo.template($("#message").html());

<script type="text/kendo-template" id="message">
    <div class="k-widget k-tooltip k-tooltip-validation k-invalid-msg field-validation-error" style="margin: 0.5em; display: block; " data-for="#=field#" data-valmsg-for="#=field#" id="#=field#_validationMessage">
        <span class="k-icon k-warning"> 
        </span>
            #=message#
        <div class="k-callout k-callout-n">
        </div>
    </div>
</script>

As far as why user input is disappearing, I assume that:

this.cancelChanges();

may have something to do with it. I believe this does just what it says and cancels all changes. Which would reset your grid and remove all user input.

One thing to note: The code in the ModelState (also the key in your $.each) must be the same name as the view model property being used for the column you want to display the error on.

With modifying of another answer and trying around, I constructed a working solution:

Location Edit.cshtml Grid Razor:

.DataSource(ds => ds
    .Ajax()
    .Events(e => e.Error("onError"))
    .Model(m =>
        {
            m.Id(e => e.ID);
            ...
        })
    .Create(create => create.Action("CreateInLine", "Location"))
    .Read(...)
    .Update(update => update.Action("UpdateInLine", "Location"))
    .Destroy(...)
)

Location Edit.cshtml js:

<script type="text/javascript">
function onError(e, status) {
    if (e.errors) {
        var message = "Error:\n";

        var grid = $('#locationGrid').data('kendoGrid');
        var gridElement = grid.editable.element;

        var validationMessageTemplate = kendo.template(
            "<div id='#=field#_validationMessage' " +
                "class='k-widget k-tooltip k-tooltip-validation " +
                    "k-invalid-msg field-validation-error' " +
                "style='margin: 0.5em;' data-for='#=field#' " +
                "data-val-msg-for='#=field#' role='alert'>" +
                "<span class='k-icon k-warning'></span>" +
                "#=message#" +
                "<div class='k-callout k-callout-n'></div>" +
            "</div>");

        $.each(e.errors, function (key, value) {
            if (value.errors) {
                gridElement.find("[data-valmsg-for=" + key + "],[data-val-msg-for=" + key + "]")
                    .replaceWith(validationMessageTemplate({ field: key, message: value.errors[0] }));
                gridElement.find("input[name=" + key + "]").focus();
            }
        });
        grid.one("dataBinding", function (e) {
            e.preventDefault();   // cancel grid rebind
        });
    }
}
</script>

LocationController.cs

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult CreateInLine([DataSourceRequest] DataSourceRequest request, LocationViewModel model)
    {
        CustomValidateModel(model);
        if (model != null && ModelState.IsValid)
        {
            var location = _repository.CreateNewInstance<Location>();
            location.ID = Guid.NewGuid();
            location.DisplayName = model.DisplayName;
            ...
            _repository.SaveChanges();
            model = MapToViewModel(location);
        }
        return Json(new[] { model }.ToDataSourceResult(request, ModelState));
    }

    private void CustomValidateModel(LocationViewModel model)
    {
        var existingEntity = _repository.GetAll<Location>()
                                            .Where(o => o.ID != model.ID)
                                            .Where(o => o.DisplayName.Equals(model.DisplayName))
                                            .FirstOrDefault();

        if (existingEntity != null)
        {
            if (existingEntity.Deleted == false)
                ModelState.AddModelError("DisplayName", "Name already exists.");
            else
                ModelState.AddModelError("DisplayName", "Name '" + existingEntity.DisplayName + "' already exists in DB, but deleted.");
        }
    }

Result:

You can try this;

DisplayName: {
    validation: {
    required: true,
    DisplayNameValidation: function (input) {
       var exists = CheckName(input.val());
       if (exists && input.is("[name='DisplayName']") && input.val() != "") {
            input.attr("data-DisplayNameValidation-msg", "Name already exists.");
            return false;
           }
         }

         return true;
    }
  }

And

function CheckName(Name) {
var exists = false;
$.ajax
    ({
        type: "POST",
        url: "CheckName",
        data: "{Name:'" + Name + "'}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        async: false,            
        error: function (msg) {
        },
        success: function (response) {
            exists = response;
        }
    });
return exists;

}

For further documentation check kendo demo site for custom validation.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!