Make a field not [Required] in certain situations? - asp.net-mvc

I have a model that includes the following property:
[Required]
public string City { get; set; }
Basically, a user selects a stored value from a dropdown. The fields in my partial view are populated with the corresponding data. In certain circumstances, the stored data will not have a value for City. I am trying to use jQuery to check that if the field is empty, to basically not require the field and to allow submission. I have tried the following:
$("#City").attr("data-val", "false");
$("#City").rules("remove", "required");
$("#City").attr("disabled", "disabled");
$("#City").attr("aria-required", "false");
$("#City").removeAttr("required");
None of these work. On submit, the proper method is hit in the controller with a ModelState.IsValid of false and an error stating that "The City field is required."
How can I use jQuery to prevent this field from being validated on submit?

Before checking whether the ModelState.IsValid, you can remove the errors on that property of the Model ModelState["City"].Errors.Clear(); Therefore meaning regardless of what errors have occurred on your City property, the model state will be valid.
Note, this fix should be applied in the controller on the server - it is not related to jQuery.

Even though there were some great suggestions from posters, I ended up reevaluating our needs and found that the Required attribute was not required for that specific property.
Thanks for your suggestions everyone.

Related

ModelState.IsValid is false because CreatedBy field is null

I have an entity with, amongst others, the fields: CreatedBy, CreatedAt, ChangedAt
Now in the view, I do not want the user to fill these fields.
My approach was to fill them on the HTTP POST Action, before ModelState.IsValid check is made and before saving the data to the database.
However, ModelState.IsValid keeps returning false no matter what. What is the right way to implement this? Should I take the validation (ModelState.IsValid) from the POST action?
One problem, many solutions (from best to worst, in my opinion).
First solution
The best way would be to use a ViewModel (a class containing only the fields which must be edited by user and / or validated).
In this case, the CreatedBy, CreatedAt, ChangedAt fields would not appear in your ViewModel class.
Second solution
If you don't want ViewModel, you can put the "not mutable by user" fields as hidden fields in your view
#Html.HiddenFor(m => m.CreatedAt)
of course, hidden fields can be changed by user, so it's always an open door to unwanted datas...
Third solution
Clean ModelState from undesired errors before checking if it's valid (should become really boring if you've many fields concerned).
if (ModelState.ContainsKey("CreatedAt")) {
ModelState["CreatedAt"].Errors.Clear();
}
//then test for ModelState.IsValid()
Other solutions
WhiteList, BlackList for model binding, or... anything I forgot !
Many projects like to separate the View Model from the Domain Model. This allows you to create a View-Model class specifically tailored for the data you want to render and/or receive in a certain action while keeping the domain model correct/consistent.
In your View-Model class you would either not define any such property as the created date (since it is not supposed to be posted but is determined in the action). Or if you use one and the same View-Model for rendering and posting, and you want to render the date, you can make the date nullable (see Alexey's answer) on the View-Model while keeping it mandatory on the domain model.
DateTime is not nullable. If you want to keep those fields as null during model binding, if there is no values for them use:
Nullable<DateTime>
or shortcut:
DateTime?

Modelstate.Isvalid showing false

I have made a web application in MVC Razor. When I post/submit the page DATA ANNOTATION validation fires on those fields also which was hidden/or not shown to user. As dataannodation [Required] validation are put on hidden properties also, I am getting False value on ModelState.IsValid. And since the project is on the verge of completion we can not change or remake the MODEL Class.
Please somebody suggest me how to achieve this..If my question is not clear please let me know.
You can use
ModelState.Remove("FieldName");
to remove entries in model state, that are related to hidden fields.
Please at least make sure, that safety of the system is not compromised by using [Bind(Exclude = "Property names")] attribute to disable binding of fields, that should not be sent from form.

MVC: How to make DropdownList field (with Chosen Plugin) Required

I have declared a parameter in my model as
[Required]
public int? param{get; set;}
and defined this on a dropdown list. Everything works fine and the data validation works, until I add the plugin, Chosen. When I add the plugin, there is no validation proior to submission. How can i keep the data validation when the plugin is applied on the Select element?
As suggested here, I went to the chose js file and changed the this.form_field_jq.hide() to 'this.form_field_jq.css("position","absolute").css("left","-9999px")'

MVC validator errors disappear by the time control is given to the controller

I have a simple model FilesModel for updating a string Description and the boolean value of a checkbox Archived for a few (already uploaded) files, and FilesModel has a validator FilesModelValidator that gets run when this data is posted. This validator does nothing more than check that each file has a description. I know that it runs and correctly returns an error for empty descriptions based on my debugging so far.
However, when control is given to the Action method in the Controller, ModelState is different from what I expect. There are no errors on the description fields, but there is one error for each checkbox that is checked: "The value 'on' is not valid for Archived."
Validation of this sort works just fine in other areas of the site, so I'm sure there's some minute thing I'm overlooking. Any suggestions as to why this may be happening and how to fix it?
Validator
public FilesModelValidator()
{
RuleFor(f => f.Files)
.Must(AllHaveADescription).WithMessage("Must have a description");
}
public static bool AllHaveADescription(Files files)
{
// This is run on postback, and returns false when any Description is empty
return files.All(f => f.Description != null && f.Description.Length > 0);
}
Controller
[HttpPost]
public virtual ActionResult Update(FilesModel model)
{
// At this point, ModelState contains an error for each checked checkbox
// and no errors for empty descriptions
if (ModelState.IsValid)
{
// Save
}
return View(model);
}
It turns out the checkbox thing was the entire problem. I found a solution to this problem elsewhere in our code, so I used it. It seems kind of hacky, but it works.
The idea is that you need to make sure that the checkbox's value is true and not "on". So do this:
<input type="checkbox" id="myCheckbox" value="true" />
Then add a hidden input with the same id with its value as false immediately after the checkbox:
<input type="hidden" id="myCheckbox" value="false" />
When a checkbox is not checked, the checkbox value does not get posted back to the server. So when the postback occurs, the server sees myCheckbox=false which is exactly what we would want in this case. When the checkbox is checked, both input values get posted to the server. But the server uses only the first value (which is the value of the checkbox itself, since we put it before the hidden field). So the server sees myCheckbox=true.
I used the following in the view rather than manually creating the checkbox:
Html.CheckBox("FieldName")
I had the same issue for items in a drop down that were linked to an Enum. I had stripped out the default value and so when someone didn't select something I got an error.
So, having said that, I think your problem might be kinda linked in that the binder is looking for a true/false when your model is expeting a yes/no or vice versa.
Two ways around this might be to change your view to be True/False or, and this is what I did, to write my own ModelBinder which does the conversion from Yes to True.
I hope this is of some help to you.

Why does the default model binder not validate fields when they are not in form data?

Let's say you have simple object like this :
public class MyObject {
public int Test { get; set; }
}
And you count on the default model binder to make sure the user does not leave the "Test" field empty when posting a form like below :
<form method="post" action="/test">
<p>
<%=Html.TextBox("Test") %>
<%=Html.ValidationMessage("Test") %>
</p>
<input id="Submit1" type="submit" value="submit" />
</form>
And this action :
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Test(MyObject o) {
return View();
}
This all works as expected when the form data contains a key for "Test" (like "Test=val" or "Test=")
But if the key is not in the form data, then the validation doesn't occur. So in case of an empty post request or a request with a data like AnotherField=foo the property on the model object defaults to the type's default value (in this case 0). And ModelState.IsValid returns true.
This is, IMO, not the behaviour one would expect.
So what do you suggest to change this behaviour?
Edit :
Keep in mind that a malicious user can just tamper the form data easily with FireBug or Tamper Data plugin to pass the default model binder's validations, which could cause some security problems.
It is not validating the fields by design, unfortunately. Please take a look at this Codeplex issue that I've found and commented on.
It is really unfortunate, that MS has decided this is the correct behaviour for their model binder.
I believe the default model binder should validate the whole entity instead of just the posted data.
You might consider using xVal to perform the necessary mix of client- and server-side validation. With it, you can add an attribute to your Test property dictating what sort of validation rules (required, regex validation, etc.) apply to it and then, with a little more work, get it to generate JavaScript rules for you as well as pretty easily perform model validation.
You're already aware that you're violating a rule of development - never trust client input. There's really no way around it.
Client-side validation (preventing a round trip to find out that there's an error) is nice-to-have, server-side validation verifying that things truly are in order is a must-have.
i hope its by design because I am about to start relying on this behavior!
in one instance i have two controls which post back the following fields :
ShippingAddress.FirstName
ShippingAddress.LastName
ShippingAddress.Line1
ShippingAddress.Line2
BillingAddress.Email
BillingAddress.FirstName
BillingAddress.LastName
BillingAddress.Line1
BillingAddress.Line2
Note: Billing Address does not have email displayed, even though the underlying model of course still has it
If I have Email as a [Required] data annotation in my model then it will only complain when it is missing from Billing Address.
But I definitely see your point! I'm just relying on it for this one scenario here!
After researching all the different ways to get the form values into my controller methods, I discovered that the "safest" was to explicitly define each form field as a parameter to the controller. A side effect is that if a form does NOT have one of the fields, it will throw an exception - which would solve your problem.

Resources