简体   繁体   中英

asp mvc core 3 Client side validation for a custom attribute validation

I've created a custom validation attribute like so:

public class UniqueTitleAttribute : ValidationAttribute
    {
        protected override ValidationResult IsValid(
           object value, ValidationContext validationContext)
        {
            var context = (MyDBContext)validationContext.GetService(typeof(MyDBContext));
            var entity = context.Pages.SingleOrDefault(e => e.Title == value.ToString());

            if (entity != null)
            {
                return new ValidationResult(GetErrorMessage(value.ToString()));
            }
            return ValidationResult.Success;
        }

        public string GetErrorMessage(string title)
        {
            return $"Title {title} is already in use.";
        }
    }

And the in the model:

[UniqueTitle]
public string Title { get; set; }

And it works great, however I would also like to be able to add client side validation?

In the custom validation attribute, implement the IClientModelValidator interface and create an AddValidation method. In the AddValidation method, add data- attributes for validation as follows:

public class UniqueTitleAttribute : ValidationAttribute, IClientModelValidator
{
    protected override ValidationResult IsValid(
       object value, ValidationContext validationContext)
    {
        var context = (ApplicationDbContext)validationContext.GetService(typeof(ApplicationDbContext));
        var entity = context.Articles.SingleOrDefault(e => e.Title == value.ToString());

        if (entity != null)
        {
            return new ValidationResult(GetErrorMessage(value.ToString()));
        }
        return ValidationResult.Success;
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        Type obj = typeof(Article);
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        MergeAttribute(context.Attributes, "data-val", "true");
        MergeAttribute(context.Attributes, "data-val-uniquetitle", GetErrorMessage());
    }
    private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
    {
        if (attributes.ContainsKey(key))
        {
            return false;
        }

        attributes.Add(key, value);
        return true;
    }

    public string GetErrorMessage()
    {
        return $"The title is already in use.";
    }
    public string GetErrorMessage(string title)
    {
        return $"Title {title} is already in use.";
    }
}

Add a method to jQuery validation library. It uses addMethod() method to specify our own validation function. The validation function receives the value entered in the title textbox. It then performs the validation and returns a boolean value.

<div class="row">
<div class="col-md-4">
    <form method="post" asp-action="CreateArticle">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>

        <div class="form-group">
            <label asp-for="Title" class="control-label"></label>
            <input asp-for="Title" class="form-control" />
            <span asp-validation-for="Title" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="Author" class="control-label"></label>
            <input asp-for="Author" class="form-control" />
            <span asp-validation-for="Author" class="text-danger"></span>
        </div>

        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>
</div>
</div>

@section Scripts
{
   @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
  <script type="text/javascript">
    var titlelist = @Html.Raw(Json.Serialize(ViewBag.TitleList));
    $.validator.addMethod("uniquetitle",
    function (value, element, param) {

        if (titlelist.includes(value)) {
            return false;
        }
        else {
            return true;
        }
    });
    $.validator.unobtrusive.adapters.addBool("uniquetitle");
  </script>
}

Save the TitleList in ViewBag in the Get method of the view,in order to judge if the title is in use from js:

public IActionResult CreateArticle()
    {
        ViewBag.TitleList = _context.Articles.Select(a => a.Title).ToList();
        return View();
    }

Result: 在此处输入图像描述

You have to use jquery and unobtrusive client side validation so fetch those urls in 
your page.

Use like 
<label asp-for="Name"></label>
<input asp-for="Name"/>
<span asp-validation-for="Name"></span>

Here i have taken example of Name as validation will fire on Name property but you can 
change property on which you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM