私はパーティーにいくぶん遅れています (ほんの数年) まだ...
最も適切な解決策は確かに作成する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();
};
});
これで時間が節約できることを願っています。