Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a variable to validator

I am trying to set-up a remote validation similar to the one in this example: Example

My application has a twist however, my form elements are dynamically generated, therefore this tag:

[Remote("doesUserNameExist", "Account", HttpMethod = "POST", ErrorMessage = "User name already exists. Please enter a different user name.")]

is not set in stone, I need to vary the ErrorMessage for example and preferably vary the action. Is it possible, or would you suggest taking the long-way, meaning to implement the whole ajax validation on my own.

Any suggestions are appreciated.

like image 319
RealityDysfunction Avatar asked Feb 28 '14 19:02

RealityDysfunction


2 Answers

If you need to have a dynamic error message then you could return this as string from your validation action:

public ActionResult DoesUserNameExist(string username)
{
    if (Exists(uasername))
    {
        string errorMessage = "Some dynamic error message";
        return Json(errorMessage, JsonRequestBehavior.AllowGet);
    }

    return Json(true, JsonRequestBehavior.AllowGet);
}

And if you need even more flexibility such as invoking dynamic dynamic actions, then you're better of rolling your custom validation solution instead of relying on the built-in Remote attribute.

like image 80
Darin Dimitrov Avatar answered Oct 20 '22 12:10

Darin Dimitrov


You can inherit from RemoteAttribute and make it fetch the required values from a service or factory according to your own logic. Here is an example:

    [AttributeUsage(AttributeTargets.Property)]
    public class MyRemoteAttribute : RemoteAttribute
    {
        public MyRemoteAttribute(Type type, string propertyName)
            : base(MyRemoteAttributeDataProvider.GetAttributeData(type,propertyName).Action,               MyRemoteAttributeDataProvider.GetAttributeData(type,propertyName).Controller)
        {
            var data = MyRemoteAttributeDataProvider.GetAttributeData(type,propertyName);
            base.ErrorMessage = data.ErrorMessage;
            base.HttpMethod = data.HttpMethod;
        }
    }

    public static class MyRemoteAttributeDataProvider
    {
        public static RemoteAttributeData GetAttributeData(Type type
           , string propertyName)
        {
            //this is where you are going to implement your logic im just implementing                 as an example
            //you can pass in a different type to get your values. For example you can  pass in a service to get required values.

            //property specific logic here, again im going to implement to make this
            //specification by example
           var attrData = new RemoteAttributeData();            
           if(propertyName == "MyOtherProperty")
           {
                attrData.Action = "MyOtherPropertyRelatedAction";
                attrData.Controller = "MyOtherPropertyRelatedController";
                attrData.ErrorMessage = "MyOtherPropertyRelated Error Message";
                attrData.HttpMethod = "POST";
           }            
           else 
           {            
                attrData.Action = "UserNameExists";
                attrData.Controller = "AccountController";
                attrData.ErrorMessage = "Some Error Message";
                attrData.HttpMethod = "POST";
           }
           return attrData;
        }
    }

    public class RemoteAttributeData
    {
        public string Controller { get; set; }
        public string Action { get; set; }
        public string HttpMethod { get; set; }
        public string ErrorMessage { get; set; }
    }

And this is how you are supposed to use is:

public class RegisterViewModel
{
    [Required]
    [Display(Name = "User name")]
    [MyRemote(typeof(RegisterViewModel),"UserName")]
    public string UserName { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

    [Required]
    [MyRemote(typeof(RegisterViewModel),"MyOtherProperty")]
    public string MyOtherProperty { get; set; }
}

As I also mentioned above at the commentary. You should specialize that provider according to your needs.

I hope this helps.

UPDATE: I update the implementation based on your comment, so that it takes a property name and does some property name specific wiring.

like image 2
Kemâl Gültekin Avatar answered Oct 20 '22 10:10

Kemâl Gültekin