javascript 如何在 ASP.NET MVC 验证期间提供警告?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13319648/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 18:24:56  来源:igfitidea点击:

How to provide warnings during validation in ASP.NET MVC?

c#javascriptasp.net-mvcvalidation

提问by Alex

Sometimes user input is not strictly invalid but can be considered problematic.

有时用户输入并非严格无效,但可以被认为是有问题的。

For example:

例如:

  • A user enters a long sentence in a single-line Namefield. He probably should have used the Descriptionfield instead.
  • A user enters a Namethat is very similar to that of an existing entity. Perhaps he's inputting the same entity but didn't realize it already exists, or some concurrent user has just entered it.
  • 用户在单行Name字段中输入长句。他可能应该使用该Description领域
  • 用户输入的 aName与现有实体的非常相似。也许他正在输入相同的实体但没有意识到它已经存在,或者某个并发用户刚刚输入了它。

Some of these can easily be checked client-side, some require server-side checks.

其中一些可以很容易地在客户端检查,有些需要服务器端检查。

What's the best way, perhaps something similar to DataAnnotationsvalidation, to provide warnings to the user in such cases?The key here is that the user has to be able to override the warning and still submit the form (or re-submit the form, depending on the implementation).

在这种情况下向用户提供警告的最佳方法是什么,也许类似于DataAnnotations验证这里的关键是用户必须能够覆盖警告并仍然提交表单(或重新提交表单,取决于实现)。

The most viable solution that comes to mind is to create some attribute, similar to a CustomValidationAttribute, that may make an AJAX call and would display some warning text but doesn't affect the ModelState. The intended usage is this:

想到的最可行的解决方案是创建一些类似于 的属性,CustomValidationAttribute它可以进行 AJAX 调用并显示一些警告文本,但不会影响ModelState. 预期用途是这样的:

[WarningOnFieldLength(MaxLength = 150)]
[WarningOnPossibleDuplicate()]
public string Name { get; set; }

In the view:

在视图中:

@Html.EditorFor(model => model.Name)
@Html.WarningMessageFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)

So, any ideas?

那么,有什么想法吗?

回答by Serge Belov

Overall Design

整体设计

To start with, I believe you would have to track somehow if the user choose to ignore the warnings. A simple and transparent way to do that is to have an Ignore Warningscheck-box, which user would have to check before submit. Another option is a have them submit the form two times and ignore the warnings on the second submit; then you'd probably need an IgnoreWarningshidden field. There could be other designs, but for the sake of simplicity I'll go with the first option.

首先,我相信如果用户选择忽略警告,您将不得不以某种方式进行跟踪。一个简单而透明的方法是有一个忽略警告复选框,用户必须在提交前检查。另一种选择是让他们提交两次表单并忽略第二次提交时的警告;那么您可能需要一个IgnoreWarnings隐藏字段。可能还有其他设计,但为了简单起见,我将采用第一个选项。

In short, the approach is to create

简而言之,方法是创建

  • A custom data annotation attribute for all view models supporting the warning type of validation;
  • A known base class which the view models will inherit from;
  • We'll have to duplicate the logic in JavaScript for each custom attribute.
  • 支持警告类型验证的所有视图模型的自定义数据注释属性;
  • 视图模型将从中继承的已知基类;
  • 我们必须为每个自定义属性复制 JavaScript 中的逻辑。

Please note that the code below just illustrates the approach and I have to assume quite a lot of things without knowing the full context.

请注意,下面的代码只是说明了该方法,我必须在不了解完整上下文的情况下假设很多事情。

View Model

查看模型

In this scenario it's best to separate a view model from an actual model which is a good idea anyway. One possible approach is to have a base class for all view models which support warnings:

在这种情况下,最好将视图模型与实际模型分开,无论如何这是一个好主意。一种可能的方法是为所有支持警告的视图模型创建一个基类:

public abstract class BaseViewModel
{
    public bool IgnoreWarnings { get; set; }
}

The key reason a model needs to be separate is that there's little sense in storing the IgnoreWarningsproperty in your database.

模型需要分离的关键原因是将IgnoreWarnings属性存储在数据库中几乎没有意义。

Your derived view model will then look as follows:

您的派生视图模型将如下所示:

public class YourViewModel : BaseViewModel
{
    [Required]
    [StringLengthWarning(MaximumLength = 5, ErrorMessage = "Your Warning Message")]
    public string YourProperty { get; set; }
}

StringLengthWarningis a custom data annotation attribute for server and client-side validation. It just supports the maximum length and can easily be extended with any other necessary properties.

StringLengthWarning是用于服务器和客户端验证的自定义数据注释属性。它只支持最大长度,并且可以轻松扩展任何其他必要的属性。

Data Annotation Attribute

数据注释属性

The core of the attribute is IsValid(value, validationContextmethod.

属性的核心是IsValid(value, validationContext方法。

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class StringLengthWarningAttribute : ValidationAttribute, IClientValidatable 
{
    public int MaximumLength { get; set; }

    public override bool IsValid(object value)
    {
        return true;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var model = validationContext.ObjectInstance as BaseViewModel;
        var str = value as string;
        if (!model.IgnoreWarnings && (string.IsNullOrWhiteSpace(str) || str.Length > MaximumLength))
            return new ValidationResult(ErrorMessage);
        return base.IsValid(value, validationContext);
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new StringLengthWarningValidationRule(MaximumLength, ErrorMessage);
    }
}

The attribute implements IClientValidatableand utilizes a custom client validation rule:

该属性实现IClientValidatable并利用自定义客户端验证规则:

public class StringLengthWarningValidationRule : ModelClientValidationRule
{
    public StringLengthWarningValidationRule(int maximumLength, string errorMessage)
    {
        ErrorMessage = errorMessage;
        ValidationType = "stringlengthwarning";
        ValidationParameters.Add("maximumlength", maximumLength);
        ValidationParameters.Add("ignorewarningsfield", "IgnoreWarnings");
    }
}

Client-side JavaScript

客户端 JavaScript

Finally, to make it work, you'll need the following JavaScript referenced from your view:

最后,要使其工作,您需要从您的视图中引用以下 JavaScript:

$(function () {
    $.validator.addMethod('stringlengthwarning', function (value, element, params) {
        var maximumlength = params['maximumlength'];
        var ignorewarningsfield = params['ignorewarningsfield'];

        var ctl = $("#" + ignorewarningsfield);
        if (ctl == null || ctl.is(':checked'))
            return true;
        return value.length <= maximumlength;
    });

    $.validator.unobtrusive.adapters.add("stringlengthwarning", ["maximumlength", "ignorewarningsfield"], function (options) {
        var value = {
            maximumlength: options.params.maximumlength,
            ignorewarningsfield: options.params.ignorewarningsfield
        };
        options.rules["stringlengthwarning"] = value;
        if (options.message) {
            options.messages["stringlengthwarning"] = options.message;
        }
    });

}(jQuery));

The JavaScript makes some assumptions you might want to revisit (the check-box name, etc).

JavaScript 做了一些您可能想要重新访问的假设(复选框名称等)。

UPDATE: HTML Helpers

更新:HTML 助手

To display the validation messages separately for errors and warnings, a couple of helpers will be necessary. The following class provides a sample:

要分别显示错误和警告的验证消息,需要几个助手。以下类提供了一个示例:

public static class  MessageHelpers
{
    public static MvcHtmlString WarningMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] != null)
            return htmlHelper.ValidationMessageFor(expression);
        return MvcHtmlString.Empty;
    }

    public static MvcHtmlString ErrorMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        if (htmlHelper.ViewData.ModelState["IgnoreWarnings"] == null)
            return htmlHelper.ValidationMessageFor(expression);
        return MvcHtmlString.Empty;
    }
}

In the view they can be used as usual:

在视图中,它们可以照常使用:

        @Html.EditorFor(model => model.YourProperty)
        @Html.ErrorMessageFor(model => model.YourProperty)
        @Html.WarningMessageFor(model => model.YourProperty)

回答by VJAI

You could use the dependsfunction of jquery validation to simplify your life.

您可以使用dependsjquery 验证功能来简化您的生活。

Ex.

前任。

@Html.LabelFor(m => m.UserName)
@Html.TextBoxFor(m => m.UserName)
@Html.ValidationMessageFor(m => m.UserName)

<label>Ignore Warnings</label>
<input id="ignore-warnings" type="checkbox" />

<script>
  $(function () {
    $("#UserName").rules("add", {
      minlength: {
        param: 6,
        depends: function (element) {
          return !$("#ignore-warnings").attr('checked');
        }
      },

      // server side remote validation for duplicate check
      remote: {
        param: '/account/duplicate',
        depends: function (element) {
          return !$("#ignore-warnings").attr('checked');
        }
      }
    });
  });
</script>

回答by brains911

Just a quick comment on the possible re-submit implementation you mentioned...

只是对您提到的可能的重新提交实施的快速评论......

For the "did you mean to do this?" validation type, from a user's perspective, having to re-submit a form based off an assumption that they made a mistake could be very annoying. I would only implement this 'pseudo-validation' on the client side with javascript and (hopefully quick) ajax calls if you have to hit the server.

对于“你是故意这样做的吗?” 验证类型,从用户的角度来看,必须基于他们犯了错误的假设重新提交表单可能非常烦人。如果您必须访问服务器,我只会在客户端使用 javascript 和(希望是快速的)ajax 调用来实现这种“伪验证”。

I would also attempt to display the warnings on the input's blur/change events so they show before the user hits submit. Maybe not practical in all situations, but I just thought i'd throw it out there.

我还会尝试在输入的模糊/更改事件上显示警告,以便它们在用户点击提交之前显示。也许在所有情况下都不实用,但我只是想我会把它扔在那里。

回答by Peter Smith

This is just a sketch of a possible solution. There are plenty of examples of adding custom attributes (including above) so I'll skip that bit.

这只是一个可能的解决方案的草图。有很多添加自定义属性的例子(包括上面的),所以我会跳过那一点。

It may be possible to add the use of ignore in the jQuery validator function.

可以在jQuery 验证器函数中添加 ignore 的使用。

Then use

然后使用

$("form").validate({  
ignore: ".warning-only"
});

and use the client side validator to add the 'warning-only' class after a first pass through the validator. This should then allow the form to be sent to the server.

并在第一次通过验证器后使用客户端验证器添加“仅警告”类。这应该允许将表单发送到服务器。

As I say, just a sketch, but it is something I have been researching for furture use.

正如我所说,只是一个草图,但这是我一直在研究以备将来使用的东西。

回答by Tom Regan

Here is a way to do a warning without writing any server-side code. Add the class "ignore-validation" to the desired invalid elements on form submit, and in your custom validation method return "true" if the element has this class (if it has the class it means the form was submitted once). You'll also need to remove the "ignore-validation" class from #IdOfInput on blur or change, depending upon the kind of control it is, that bit of code is not represented here:

这是一种无需编写任何服务器端代码即可发出警告的方法。在表单提交时将类“ignore-validation”添加到所需的无效元素中,如果元素具有此类,则在您的自定义验证方法中返回“true”(如果具有该类,则表示表单已提交一次)。您还需要在模糊或更改时从#IdOfInput 中删除“ignore-validation”类,具体取决于控件的类型,此处未表示该位代码:

<script type="text/javascript">    
$.validator.addMethod('isValidCustomMethod', function (value, element) {
        if($(element).hasClass('ignore-validation')){
            return true;
        }
        var isValid = false;    //your code to do validation would actually go here
        return isValid;
    });

$(document).ready(function () {

    $('#IdOfInput').rules('add', { isValidCustomMethod: true, messages: { isValidCustomMethod: 'Your warning message here'} });

    $('form').submit(function () {
                    $(this).validate().invalidElements().each(function () {
                        if($(this).attr('id')=='IdOfInput'){
                            $(this).addClass('ignore-validation');
                        }
                    });
                });
        }); 
    </script>