Validating textbox only if checkbox is checked using MVC - c#

I have a ViewModel with properties for a TextBox and a Checkbox:
public bool SendAlerts { get; set; }
public string EmailAddress { get; set; }
I need to validate the EmailAddress field (textbox) to ensure there is an email address ONLY if the checkbox in my view (which binds to the SendAlerts property) is checked.
If the checkbox is not checked, then it doesn't matter if the EmailAddress textbox is empty.
How do I go about implementing this conditional validation? I am using DataAnnotations against some of the other properties in my ViewModel, like a straight forward 'Required' annotation (but I can't use that for this scenario as it's conditional).
I have used CustomValidation for a couple other properties in my view model i.e.
public static ValidationResult IsTitleValid(object value)
{ ... }
However, I only have 1 object value with this approach, rather than being able to reference both checkbox AND textbox values.
What's the best way to approach this using MVC?

We were recently forced to do similar things at work, and could not find a better solution than the following:
http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx
Updated to MVC3 here:
http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx
Basically you introduce a new attribute, RequiredIf. With this solution you get client-side validation as well.

Related

What is the best pratice to change a field value when a form is submitted in MVC?

I have a lot of fields in my View that are masked with jquery MaskedInput. They're masked because the user need to see it with a mask, but I need to remove these masks before commiting the value in my database.
I don't want to mess up the code, since this is one of the most importants Views in my project.
So what's the best pratice to do this?
Suppose I have this Model:
public class MyViewModel {
public string MyMaskedProperty { get; set;}
}
And this code in View:
#Html.TextboxFor(x=> x.MyMaskedProperty, new { #class="myMask"} )
Should I:
Remove the mask on my View, using javascript, before the form is subimitted
Remove the mask on my Model, changing the get of MyMaskedProperty to return an unmasked value
Remove the mask on my Controller, since it need to be unmasked only from here and beyond
Something better than the 3 solutions above.
Thanks in advance!
Similar to the second option, you might simply add a read-only field to your view model:
public class MyViewModel {
public string MyMaskedProperty { get; set;}
public string MyUnmaskedProperty
{
get
{
// return an "unmasked" version of MyMaskedProperty
}
}
}
Even if you were to modify the value with JavaScript, you can't really implicitly trust that and would want to validate server-side anyway. And doing it in the controller isn't ideal because that's just procedural code that would need to be repeated all over the place. Following the advice to "keep your controllers light and your models heavy", this logic really belongs on the model.
The model itself can be constructed from any version of the data, really. As long as the information used to construct the model can effectively construct it, then the model can expose all sorts of operations and properties for manipulating and viewing that information.

Data annotation to check dependent property is value

My requirement is to validate a field depending on Ajax return success or failure message.
I have hidden property IsValidEmployeenumber is set 'true' or 'false' from Ajax call.
[XXX('IsValidEmployeeNumber', 'true')] //Please suggest
public string EmployeeNumber { get; set; }
public string IsValidEmployeeNumber { get; set; }
May I know is there a native MVC data annotation available that will take dependent property name and expected value.
Thanks,
No. There is no such native annotation. You can make your own, which will take as a paramter the name of the property on which the validation depends, and then when applying, pass the appropriate property name.
The way to do this is to create a custom annotation class deriving from ValidationAttribute, and making a constructor which takes as a parameter the name of the dependent property, and then override the IsValid method, in which you get the value of the dependent property using reflection, and write your custom validation logic.
Now, this will work for server side validation. But you need to do a lot more if you need client side validation as well, which is beyond the scope of this question.

Change name the For helper methods create

I am making a form with MVC and am using the [ControlType]For([expression]) helper methods (EG Html.TextBoxFor(...))
To bind the data to the controls I am using the following ViewModel:
public class UserViewModel
{
//The Model that will be used to bind data to the elements
public UserModel User { get; set; }
//Used to bind selectable options to DropDownLists
public SelectList DescentTypes { get; set; }
public SelectList GenderTypes { get; set; }
}
When using this the name of the controls get set to name="Property.SubProperty" (EG name="User.Id") but I would rather it show as name="Id" on my html form.
Is it possible to do this without having to write a lot of custom code so the framework can translate it back to the ViewModel (UserViewModel) or just the Model (User) itself?
I'd advise leaving the default naming in place unless you have a very good reason to alter it. IDs (which it appears your question is leaning towards) are more flexible.
Changing IDs
IDs aren't submitted with a form, so you can set them as desired without breaking model binding. By default, they are hierarchical, but you can override them inline:
#Html.TextBoxFor( o => o.UserName, new { id = "foo" } )
Of course, this is manual work.
If the big concern is external JS/CSS, I'd suggest using class names and data-* attributes in your (CSS/jQuery/whatever) selectors rather than IDs.
#Html.TextBoxFor( o => o.User.UserName, new { data_role="grand-total" } )
It's still manual, but it's descriptive and independent of an ID.
Sometimes I use a snippet of script in my views to initialize a larger JS class with data that is most easily available directly within the view. This lets the bulk of the script reside in an external file while allowing dynamic values to be used to initialize it. This is useful for more than just IDs.
Altering Generated Markup and Binding
For reference, let's say you wanted to change ID and name.
Write your own HtmlHelper extension methods to create the markup you want. You could probably wrap the existing methods that do not take an expression and pass explicit values to them to indicate the name that you want.
Write your own ModelBinder to map the raw form collection.
Determine a strategy for dealing with hierarchical objects (which is the main reason the naming convention exists in the first place).
Item #3 could be addressed by decorating properties to indicate how the naming should be performed and how model binding should map. This could become complicated quickly.
public class UserViewModel
{
// use this metadata to determine how to handle properties on this member
[Flatten]
public UserModel User { get; set; }
public SelectList DescentTypes { get; set; }
public SelectList GenderTypes { get; set; }
}
Alternatives
Flatten your view model by adding User's properties directly to it. It looks like your are composing your view model from domain model(s). This isn't usually a good idea. I'd suggest reading the pros/cons of binding directly to domain models.
Leave the naming alone. It really isn't hurting anything and it makes life easy. You can avoid ever directly working with names/IDs in your client code by using helper methods.
For example:
// JavaScript + Razor
var name = "#Html.NameFor( o => o.User.Id )";
alert(name);

Accessing Validation.HasError from ViewModel with WPF MVVM

So I admit I've searched a bit and can't find the answer I am looking for. I feel like I am likely searching for the wrong tags.
I have a View that has a text box that applies some Validation via a validation class which implements ValidationRule. I have it properly validating and my text box highlights/tooltips appropiately.
Now that I have it validating, I thought maybe I could block a Submit button from being enabled while the Validation.HasError = true. My ViewModel has no knowledge of this ValidationRule, nor that the ValidationRule has returned false, "some error message". What is the proper way of doing this now? I'd prefer to keep the validation out side of my "Model" and leave it in the ValidationRule class.
Can I create a boolean property "HasValidationError" and set it to true when the Validation.HasError is set to true?
I suggest you put validation logic in ViewModel and using IDataErrorInfo to handle validation for UI. In our application, Validation is an independent service.
The benefit is you have full control to handle ViewModel level error and property level error. Even you find a way associate ViewModel's hasValidationError to all controls' ValidationRule, there is still a potential issue that your ViewModel's error only dependent on UI rather than its real logic, which means, before your UI validates the ViewModel, you can never tell whether ViewModel is correct.
I agree with Bill Zhang, when you are using the MVVM pattern, the validation logic should reside in the view model. The reasons are many, but the main one is that validation of a view should be testable, and it is much easier to test a view model than a view.
Enough with the preaching, lets see some code. You can have a look at my article Zip My Code on CodeProject where I validate in the view model. I can register a validator like this:
class ExcludeItemDialogViewModel : DialogViewModelBase
{
public ExcludeItemDialogViewModel(string title, string excludeItem)
{
AddValidator(() => ExcludedItem, new NotNullOrEmptyValidationRule());
// Code removed for clarity...
}
// Code removed for clarity...
}
Calling the method AddValidator will register a validator for a specific property in the view model, in this case ExcludedItem. The validation rule would look like this:
class NotNullOrEmptyValidationRule : IValidationRule
{
public string ErrorMessage { get; private set; }
public bool Validate(object value)
{
string valueText = value as string;
if (string.IsNullOrEmpty(valueText))
{
ErrorMessage = Resources.NotNullValidationRule_Error;
return false;
}
ErrorMessage = string.Empty;
return true;
}
}

Databinding to model, with custom validation attributes - when to bind & validate?

I'm a bit new to WinForms databinding & custom validation.
Say I have a simple model in my domain:
public class SecurityObject
{
[StringLength(25)]
public string Name { get; set; }
public bool HasAccess { get; set; }
}
The Name property is data-bound to a TextBox. I would like apply the custom attribute validation so I can show a ToolTip when the validation is violated. (NOTE: yes I know I can set the MaximumLength property on the textbox, and plan to, but this is not my question right now.)
My question is, at what point should be validation be triggered?
Doesn't seem like it can be triggered in TextBox_Validating(..), because at that point, the new value hasn't bee written back to the model.
It could be triggered at TextBox_Validated(..) because the value has been written back to the model by then. However this seems inappropriate because the TextBox thinks it is valid, while the model it's bound to is not - seems fishy to me.
I guess you could disable the automatic binding, then trigger it manually within TextBox_Validating(...) by calling DataBinding.WriteValue(...) - but this seems a shame to go to so much extra effort and defeats half the point of data binding in the first place.
So, what is the recommended way to run model validation when databound?
IMO the validating event is where validation should be happening.
Doesn't seem like it can be triggered in TextBox_Validating(..), because at that point, the new value hasn't bee written back to the model.
Doesn't matter if the value has actually been set in the model, does it? What about this:
ValidationContext vc = new ValidationContext(myEntity, null, null);
vc.MemberName = "myProperty";
Boolean isValid = Validator.TryValidateProperty(formPropertyValue, vc, null);

Categories

Resources