49

ユーザー入力が厳密には無効ではなくても、問題があると見なされる場合があります。

例えば:

  • Nameユーザーが 1 行のフィールドに長い文を入力します。彼はおそらく、Description代わりにフィールドを使用する必要がありました。
  • ユーザーはName、既存のエンティティと非常によく似た を入力します。おそらく、彼は同じエンティティを入力していますが、それが既に存在していることに気付いていないか、または同時ユーザーが入力したばかりです。

これらの中には、クライアント側で簡単にチェックできるものもあれば、サーバー側のチェックが必要なものもあります。

そのような場合にユーザーに警告を提供するための最良の方法DataAnnotations、おそらく検証に似たものは何ですか? ここで重要なのは、ユーザーが警告を無効にしてフォームを送信できる (または実装によってはフォームを再送信できる) 必要があるということです。

頭に浮かぶ最も実行可能な解決策はCustomValidationAttribute、AJAX 呼び出しを行う可能性があり、警告テキストを表示する可能性がありますが、ModelState. 使用目的は次のとおりです。

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

ビューで:

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

それで、何かアイデアはありますか?

4

5 に答える 5

51

全体的なデザイン

まず、ユーザーが警告を無視することを選択した場合、何らかの方法で追跡する必要があると思います。これを行う簡単で透過的な方法は、ユーザーが送信前にチェックする必要がある[警告を無視]チェックボックスを設定することです。もう 1 つのオプションは、フォームを 2 回送信し、2 回目の送信では警告を無視することです。その場合、おそらくIgnoreWarnings隠しフィールドが必要になるでしょう。他のデザインもあるかもしれませんが、簡単にするために最初のオプションを使用します。

要するに、アプローチは作成することです

  • 警告タイプの検証をサポートするすべてのビュー モデルのカスタム データ注釈属性。
  • ビュー モデルが継承する既知の基本クラス。
  • カスタム属性ごとに、JavaScript でロジックを複製する必要があります。

以下のコードはアプローチを示しているだけであり、完全なコンテキストを知らなくてもかなり多くのことを想定する必要があることに注意してください。

モデルを見る

このシナリオでは、ビュー モデルを実際のモデルから分離することをお勧めします。これはとにかく良い考えです。考えられるアプローチの 1 つは、警告をサポートするすべてのビュー モデルの基本クラスを用意することです。

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

モデルを分離する必要がある主な理由は、IgnoreWarningsプロパティをデータベースに保存する意味がほとんどないからです。

派生ビュー モデルは次のようになります。

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

StringLengthWarningサーバー側およびクライアント側の検証用のカスタム データ注釈属性です。最大長をサポートするだけで、他の必要なプロパティで簡単に拡張できます。

データ注釈属性

属性のコアは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);
    }
}

この属性IClientValidatableは、カスタム クライアント検証規則を実装して利用します。

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

クライアント側 JavaScript

最後に、これを機能させるには、ビューから次の 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));

JavaScript は、再訪したくなるかもしれないいくつかの仮定を行います (チェックボックス名など)。

更新: HTML ヘルパー

エラーと警告の検証メッセージを別々に表示するには、いくつかのヘルパーが必要になります。次のクラスはサンプルを提供します。

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;
    }
}

ビューでは、通常どおり使用できます。

        @Html.EditorFor(model => model.YourProperty)
        @Html.ErrorMessageFor(model => model.YourProperty)
        @Html.WarningMessageFor(model => model.YourProperty)
于 2012-11-13T11:16:00.947 に答える
4

jquery 検証の機能を使用してdepends、生活を簡素化できます。

元。

@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>
于 2012-11-13T14:21:55.103 に答える
3

あなたが言及した可能な再送信の実装についての簡単なコメント...

「これをするつもりだったの?」ユーザーの観点からすると、ユーザーが間違いを犯したという仮定に基づいてフォームを再送信する必要があることは、非常に煩わしい場合があります。サーバーにアクセスする必要がある場合は、javascript と (できれば迅速な) ajax 呼び出しを使用して、クライアント側でこの「疑似検証」のみを実装します。

また、入力のぼかし/変更イベントに警告を表示して、ユーザーが送信する前に警告を表示しようとします。すべての状況で実用的ではないかもしれませんが、私はそれを捨てようと思いました.

于 2012-11-10T07:22:55.037 に答える
1

これは、可能な解決策の単なるスケッチです。カスタム属性 (上記を含む) を追加する例はたくさんあるので、その部分はスキップします。

jQuery バリデーター関数に ignore の使用を追加できる可能性があります。

次に使用します

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

クライアント側バリデーターを使用して、バリデーターを最初に通過した後に「警告のみ」のクラスを追加します。これにより、フォームをサーバーに送信できるようになります。

私が言ったように、ただのスケッチですが、それは私が将来の使用のために研究しているものです.

于 2012-11-13T17:01:51.500 に答える
0

サーバー側のコードを書かずに警告を出す方法を次に示します。フォーム送信時に目的の無効な要素にクラス「ignore-validation」を追加し、カスタム検証メソッドで、要素にこのクラスがある場合は「true」を返します(クラスがある場合は、フォームが一度送信されたことを意味します)。また、コントロールの種類に応じて、ぼかしまたは変更時に #IdOfInput から「無視検証」クラスを削除する必要があります。そのコードのビットはここには示されていません。

<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>
于 2013-04-09T19:08:26.000 に答える