2

を使用してカスタム検証を作成しようとしていますIClientValidatable

PhoneNumberとMobileの2つのフィールドがあります。ユーザーにどちらかまたは両方を実行してもらいたい。必要なのは1つだけですが、少なくとも1つ提供する必要があります。

私はこれまで何とかこれに到達することができました

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


        rule.ValidationParameters.Add("phone", "PhoneNumber");
        rule.ValidationParameters.Add("mobile", "MobileNumber");

        yield return rule;
    }

これにより、出力されたhtml要素に検証が適用されます

<input data-val="true" data-val-length="Mobile number must be a maximum length of 14." data-val-length-max="14" data-val-required="Landline or mobile phone number is needed." data-val-required-required="MobileNumber" id="MobileNumber" name="MobileNumber" type="text" value="">
<input data-val="true" data-val-length="Landline number must be a maximum length of 14." data-val-length-max="14" data-val-required="Landline or mobile phone number is needed." data-val-required-required="PhoneNumber" id="PhoneNumber" name="PhoneNumber" type="text" value="">

今、私はそれがすべて行われているわけではないことを知っています。しかし、送信ボタンを押そうとすると、検証が開始され、要約内に2つの検証エラーが表示されます。

バリデーターアダプターを追加する方法に少しこだわっています。

これまでのところ....私はそれが間違っていることを知っていますが

 jQuery.validator.unobtrusive.adapters.add('required',
        [$("#PhoneNumber").val(), $("#MobileNumber").val()],
        function(options) {
                    options.rules['required'] = options.params;
                    options.messages['required'] = options.message;
        });
4

1 に答える 1

1

まず、 Compare属性と同様の方法で独自の検証属性を作成する必要があります。

この属性では、他の依存プロパティを指定し、プロパティの表示名を考慮してエラーメッセージをフォーマットします。

属性は次のようになります(名前とデフォルトのエラーメッセージについてはあまり誇りに思っていません!):

public class SelectOneValidationAttribute : ValidationAttribute, IClientValidatable
{
    private const string DefaultErrorMessage = "Please enter '{0}' or '{1}'.";
    private string _otherFieldName;

    public SelectOneValidationAttribute(String otherFieldName)
        : base(DefaultErrorMessage)
    {
        _otherFieldName = otherFieldName;
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, _otherFieldName);
    }

    protected override DataAnnotationsValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo otherPropertyInfo = validationContext.ObjectType.GetProperty(_otherFieldName);
        if (otherPropertyInfo == null)
        {
            return new DataAnnotationsValidationResult("Unknown property " + _otherFieldName);
        }


        string strValue = value == null ? null : value.ToString();
        if(!String.IsNullOrEmpty(strValue))
            //validation succeeds as this field has been populated
            return null;

        object otherPropertyValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);

        string strOtherPropertyValue = otherPropertyValue == null ? null : otherPropertyValue.ToString();
        if (!String.IsNullOrEmpty(strOtherPropertyValue))
            //validation succeeds as the other field has been populated
            return null; 
        else
            //validation failed, none of the 2 fields were populated
            return new DataAnnotationsValidationResult(DefaultErrorMessage);
    }


    //Create the data attributes for the client to use
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ValidationType = "selectone",
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
        };

        rule.ValidationParameters["otherfield"] = FormatPropertyForClientValidation(_otherFieldName);

        yield return rule;
    }

    public static string FormatPropertyForClientValidation(string property)
    {
        return "*." + property;
    }
}

したがって、次のようにモデルで使用できます。

public class YourModel
{
    [SelectOneValidation("Phone")]
    public string Mobile { get; set; }

    [SelectOneValidation("Mobile")]
    public string Phone { get; set; }
}

そのコードで、エラーメッセージ「「携帯電話」または「電話」を入力してください。」および「「電話」または「携帯電話」と入力してください。」サーバー側の検証が失敗すると表示されます。(「1つ入力してください...」のように両方に同じエラーメッセージを設定できます)

クライアント側の検証を追加するには、目立たない検証用のアダプターを作成する必要があります。(目立たない検証でドキュメントを解析する前に、必ずどこかに追加してください。そうしないと、手動で解析する必要があります):

//Add an adaptor for our new jquery validator, that builds the optional parameters 
//for our validation code (the other field to look at)
$.validator.unobtrusive.adapters.add("selectone", ["otherfield"], function (options) {
    var prefix = getModelPrefix(options.element.name),
        other = options.params.otherfield,
        fullOtherName = appendModelPrefix(other, prefix),
        element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

    setValidationValues(options, "selectone", element);
});

これは、次のような目立たない検証ライブラリで定義されているユーティリティ関数のいくつかを使用しています。

function setValidationValues(options, ruleName, value) {
    options.rules[ruleName] = value;
    if (options.message) {
        options.messages[ruleName] = options.message;
    }
}

function getModelPrefix(fieldName) {
    return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}

function appendModelPrefix(value, prefix) {
    if (value.indexOf("*.") === 0) {
        value = value.replace("*.", prefix);
    }
    return value;
}

最後に、新しい検証ルールを作成しました。これは、必要な検証でフィルタリング式を設定できるため、その式がtrueと評価された場合にのみフィールドに有効のフラグが付けられます。必要な検証を参照してください。onBlur検証には、equaltoルールと同様の修正を適用する必要があります。

検証方法は、equalto検証から上記の修正を適用し、他の関連フィールドの依存セレクターを使用して必要なルールを呼び出すだけなので、フィールドが空白で依存が入力されていない場合にのみ、必要な検証はfalseを返します。

$.validator.addMethod("selectone", function (value, element, param) {
    // bind to the blur event of the target in order to revalidate whenever the target field is updated
    // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
    var otherField = $(param);
    if (this.settings.onfocusout) {
        otherField.unbind(".validate-selectone").bind("blur.validate-selectone", function () {
            $(element).valid();
        });
    }

    var otherFieldBlankFilter = ":input[name=" + otherField[0].name + "]:blank";
    return $.validator.methods.required.call(this, value, element, otherFieldBlankFilter);
});

それを気にしない場合は、フォームが送信されたときにのみ検証するかのように、必要なルールを直接使用するアダプターを作成するだけで済みます。

$.validator.unobtrusive.adapters.add("selectone", ["otherfield"], function (options) {
    var prefix = getModelPrefix(options.element.name),
        other = options.params.otherfield,
        fullOtherName = appendModelPrefix(other, prefix),
        element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

    setValidationValues(options, "required", ":input[name=" + fullOtherName + "]:blank");
});

これらすべてが整っているので、検証は機能するはずです。両方が空で送信しようとすると、両方のフィールドにエラーメッセージが表示されます。次に、それらの1つに何かを入力してタブアウトすると、両方のエラーメッセージが削除されます。

また、検証属性、目立たないアダプター、および検証ルールを変更できるため、これをニーズに適合させることができるはずです。

于 2012-12-08T13:05:12.027 に答える