14

誰かの誕生日の年/月/日のプロパティを持つビュー モデルがあります。これらのフィールドはすべて必須です。現在、生年月日を入力しないと、3 つのエラー メッセージが表示されます。

生年月日フィールド

私がやりたいことは、これらのエラー メッセージを「生年月日が必要です」という 1 つのメッセージにグループ化することです。したがって、これらのフィールドの 1 つ以上が空白の場合、常に 1 つの検証メッセージのみが表示されます。

jquery validate と unobtrusive validate を介してクライアント側の検証で機能するには、これが必要です。この質問を見ると、jquery 検証プラグインでこれが可能であることがわかります。しかし、モデルの検証属性と目立たない検証を使用してasp.net mvcでこれを達成する方法がわかりません。検証目的でプロパティをグループ化する方法が組み込まれていることを願っていますが、そうでない場合、カスタム検証属性でこれを行うことはできますか?

私の既存のモデルとビューは次のようになります。

モデル:

public class MyModel {
    [Required(ErrorMessage = "Year is required")]
    public int Year { get; set; }
    [Required(ErrorMessage = "Month is required")]
    public int Month { get; set; }
    [Required(ErrorMessage = "Day is required")]
    public int Day { get; set; }
}

景色:

<div>
    <label>Date of birth: <span style="color:red;">*</span></label>
    <div>@Html.DropDownListFor(m => m.Year, ApplicationModel.GetSelectListForDateRange(DateTime.Today.Year - 16, DateTime.Today.Year - 10), "", new{data_description="birthDate"})@Html.LabelFor(m => m.StudentBirthYear)</div>
    <div>@Html.DropDownListFor(m => m.Month, ApplicationModel.GetSelectListForDateRange(1, 12, true), "", new{data_description="birthDate"})@Html.LabelFor(m => m.StudentBirthMonth)</div>
    <div>@Html.DropDownListFor(m => m.Day, ApplicationModel.GetSelectListForDateRange(1, 31), "", new{data_description="birthDate"})@Html.LabelFor(m => m.StudentBirthDay)</div>
</div>
<div class="error-container">@Html.ValidationMessageFor(m => m.Year)</div>
<div class="error-container">@Html.ValidationMessageFor(m => m.Month)</div>
<div class="error-container">@Html.ValidationMessageFor(m => m.Day)</div>
4

4 に答える 4

9

私はパーティーにいくぶん遅れています (ほんの数年) まだ...

最も適切な解決策は確かに作成するCustomAttributeことですが、良いアドバイスを与える代わりに、死ぬまで放置する方法を示します.

カスタム属性:

public class GroupRequiredAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string[] _serverSideProperties;

    public GroupRequiredAttribute(params string[] serverSideProperties)
    {
        _serverSideProperties = serverSideProperties;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (_serverSideProperties == null || _serverSideProperties.Length < 1)
        {
            return null;
        }

        foreach (var input in _serverSideProperties)
        {
            var propertyInfo = validationContext.ObjectType.GetProperty(input);
            if (propertyInfo == null)
            {
                return new ValidationResult(string.Format("unknown property {0}", input));
            }

            var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
            if (propertyValue is string && !string.IsNullOrEmpty(propertyValue as string))
            {
                return null;
            }

            if (propertyValue != null)
            {
                return null;
            }
        }

        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = ErrorMessage,
            ValidationType = "grouprequired"
        };

        rule.ValidationParameters["grouprequiredinputs"] = string.Join(",", this._serverSideProperties);

        yield return rule;
    }
}

ViewModel:次のように、viewModel の 1 つのフィールドのみを装飾します。

    [GroupRequired("Year", "Month", "Day", ErrorMessage = "Please enter your date of birth")]
    public int? Year { get; set; }

    public int? Month { get; set; }

    public int? Day { get; set; }

Jquery:私の場合、jquery.validate.unobtrusive.customadapters.jsまたはアダプターを登録する場所にアダプターを追加する必要があります(目立たない検証が実行された後に、これをページに配置するだけです)。

(function ($) {
    jQuery.validator.unobtrusive.adapters.add('grouprequired', ['grouprequiredinputs'], function (options) {
        options.rules['grouprequired'] = options.params;
        options.messages['grouprequired'] = options.message;
    });
}(jQuery));

jQuery.validator.addMethod('grouprequired', function (value, element, params) {
    var inputs = params.grouprequiredinputs.split(',');
    var values = $.map(inputs, function (input, index) {
        var val = $('#' + input).val();
        return val != '' ? input : null;
    });
    return values.length == inputs.length;
});

そして、それはそれを行う必要があります。

これが何をするのか興味がある人のために: C# の土地では、フィールドの ID を取得してそれらを接着し,、Year フィールドのカスタム属性に入れます。

HTMLは次のようになります (C# 属性をデバッグしない場合):

<input class="tooltip form-control input dob--input-long" data-val="true" data-val-grouprequired="Please enter your date of birth" data-val-grouprequired-grouprequiredinputs="Year,Month,Day" name="Year" placeholder="YYYY" tabindex="" type="text" value="">

次に、Jquery 検証はそれらを id に分割し、それらのすべてが空でないかどうかをチェックします。

どういうわけかフィールドを無効としてマークしたいと思うでしょう(今ではフィールド属性が座っているだけとマークされます)最も適切な解決策は、コンテナ内のすべてのフィールドをクラスでラップしfield-error-wrapper、Jquery検証がロードされた後にページに以下を追加することです:

$.validator.setDefaults({
    highlight: function (element) {
        $(element).closest(".field-error-wrapper").addClass("input-validation-error");
    },
    unhighlight: function (element) {
        $(element).closest(".field-error-wrapper").removeClass("input-validation-error");
    }
});

フィールドをマークする代わりにコンテナをマークし、コンテナがマークされている場合は.input-validation-error内部のすべてのフィールドが赤くなるようにcssを書くことができます。ここでの仕事は終わったと思います。

編集:わかりましたので、バリデーターが日と月が有効であると認識し、親から無効なクラスを削除する必要があるため、フィールドのマークが解除されるもう1つの問題があるようです。バリデーターは最初に無効なフィールドをマークし、次に有効なマークを解除します。そのため、検証が行われる順序を変更しました。これをグローバルにオーバーライドすることはお勧めしません (どのような壊滅的な影響があるのか​​ わからないため)、生年月日フィールドがあるページに貼り付けるだけです。

$(function () {
    $.data($('form')[0], 'validator').settings.showErrors = function () {
        if (this.settings.unhighlight) {
            for (var i = 0, elements = this.validElements() ; elements[i]; i++) {
                this.settings.unhighlight.call(this, elements[i], this.settings.errorClass, this.settings.validClass);
            }
        }
        this.hideErrors();
        for (var i = 0; this.errorList[i]; i++) {
            var error = this.errorList[i];
            this.settings.highlight && this.settings.highlight.call(this, error.element, this.settings.errorClass, this.settings.validClass);
            this.showLabel(error.element, error.message);
        }
        if (this.errorList.length) {
            this.toShow = this.toShow.add(this.containers);
        }
        if (this.settings.success) {
            for (var i = 0; this.successList[i]; i++) {
                this.showLabel(this.successList[i]);
            }
        }
        this.toHide = this.toHide.not(this.toShow);

        this.addWrapper(this.toShow).show();
    };
});

これで時間が節約できることを願っています。

于 2015-12-02T10:52:29.787 に答える
0

こんにちは、これがあなたの要件を満たすことを願っています

//--------------------------HTML Code-----------------------------
    <form id="myform">  
        <select name="day">
            <option value="">select</option>
            <option value="1">1</option>
        <select>
             <select name="mnth">
            <option value="">select</option>
            <option value="Jan">Jan</option>
        <select>
             <select name="yr">
            <option value="">select</option>
            <option value="2015">2015</option>
        <select>
            <br/>
        <input  type="submit"  />
                    <br/>
            <div id="msg"></div>
    </form>



    //-------------------------------JS Code to validate-------------



      $(document).ready(function() {


    $('#myform').validate({
        rules: {
            day: {
                required: true
            },
            mnth: {
                required: true
            },
             yr: {
                required: true
            }
        },
          errorPlacement: function (error, element) {
            var name = $(element).attr("name");
            error.appendTo($("#msg"));
        },
        messages: {
            day: {
                required: "Date of birth is required"
            },
            mnth: {
                required: "Date of birth is required"
            },
             yr: {
                required: "Date of birth is required"
            }
        },
        groups: {
            p: "day mnth yr"
        },
        submitHandler: function(form) { // for demo
            alert('valid form');
            return false;
        }
    });

});

ここに実行例があります

于 2015-01-30T20:24:26.007 に答える
0

CustomAttributeを使用するだけでそれを行うことができます。

この属性をモデルに追加するだけです

[CustomValidation(typeof(MyModel), "ValidateRelatedObject")]

次に、次のメソッドで値を検証するルールを定義するだけです。

public static ValidationResult ValidateRelatedObject(object value, ValidationContext context)
{
    var context = new ValidationContext(value, validationContext.ServiceContainer, validationContext.Items);
    var results = new List<ValidationResult>();
    Validator.TryValidateObject(value, context, results);

    // TODO: Wrap or parse multiple ValidationResult's into one ValidationResult

    return result; 
}

詳細については、このリンクにアクセスしてください。

于 2013-09-10T19:47:48.730 に答える