ASP.NET MVC: Client validation for complex patial views - asp.net-mvc

I have this viewmodel:
public class Letter
{
public strng Name{get;set;}
[UIHint("UserSelector")]
[Required]
public List<int> Users{get;set;}
}
For rendering Letter viewmodel I use Html.EditorForModel(). EditorTemplate "UserSelector" is complex view and looks like this:
Before submitting the form I manually generate hidden field controls for selected users and it's obviously RequiredAttribute doesn't work for Users property. What's "true" way to force UserSelector view to "understand" RequiredAttribute?

you could have a another string with empty value at first, and then use it in a hidden input, then make it required. Every time client add a user from left to right, update that hidden input value like 'Usera,Userb ....'. So when client tries to submit the form, this hidden input must have value.

Related

ASP.NET Retrieving form values for the same database field Model Binding

I have a Form which will dynamically add textboxes for a particular database field. I wanted to use Model Binding to retrieve values from the Form on a Controller. I know Model Binding uses the textbox's id to retrieve values. However it's never recommended to have multiple textboxes with same ID as its unique. I have it such that in case a user needs more textboxes for the same field, they can add them dynamically by clicking a button. How do I retrieve values from these textboxes? Is there a way I can use html classes with model binding to retrieve the values instead? Or should I do it like this
public ActionResult MyAction(FormCollection form)
{
// ModelBinder will set "form" appropriately
foreach(var value in form.Getvalues("duplicatedFieldId"))
{
//do something with value
}
}
Regards

MVC: Client validation on list of object (At least one)

I want to implement client validation on a list of objects. I want to make sure that the list has at least one object, so I used custom validation as described here and made it client validable. This works well when the list is of simple datatype like an int.
That is
public List<int> var{get; set;}
With this I can include a Listboxfor in my view and when the form containing the list is submitted, client validation kicks in. However I now have a list of objects
public List<MyClass> var{get; set;}
Items are added to this list dynamically. I can therefore not have a ListBoxFor in my View. How can i display the list in my View so that that client validation picks it up?

Will Razor's EditorFor() syntactic sugar create a checkbox list in the View?

I've been jumping through hoops to add an array of checkboxes to a View in an asp.net MVC project (using a custom jQuery plugin), but just realized it might be possible using the "in-the-box" functionality of the MVC / Razor extravaganza.
Theoretically, the following should work:
If a model has an array of bool, such as:
public bool[] chicagoBoolsFools { get; set; }
...calling this in the View:
#Html.EditorFor( model => model.chicagoBoolsFools)
...should create an array of checkboxes bound to the Model member.
Is this the case only in theory, or also in actuality?
Unfortunately #Html.EditorFor doesn't even create checkboxes... Maybe I am misunderstanding you but I would try something more along the lines of this post.
Try stuffing a model with either a list of Checkboxes (represented by a string and a boolean value) or just a basic string property for each checkbox, which can then be rendered in the view using several #Html.CheckBoxFor calls.
#Html.CheckBox or #Html.CheckBoxFor are key here.

mvc modelbinding

I have an Edit action/view for my User object, but only want a few fields to be editable.
I've set up the view to bind to the User object, and am using Html.EditorFor() for the few fields that I want to be editable.
I noticed in my User object on Post:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditUser(Mynamespace.User user)
{ }
that only the fields that I provided .EditorFor() controls for actually have any data.
I tried using Html.Hidden(Model.ID) for one of the fields that i didn't want to be editable, but it is null in the new User object created from model binding.
So, my question- How do I bind where only a couple of the fields should be editable?
Thanks!
It sounds like you probably want to start thinking about using a View Model that is specific to the form/input that you're dealing with. But in the short term, ....
You could bind to a FormCollection parameter instead and copy the values manually, OR...
you can use the TryUpdateModel method to populate this existing user object with the new data.
Here's the documentation for TryUpdateModel:
http://msdn.microsoft.com/en-us/library/dd470756.aspx
It's still possible for malicious users to send phony form-values that map to real properties on your model, so to protect against this (like an employee changing his salary property with a simple form hack) you can introduce an interface that contains the white list properties that you allow.
Here's an example:
public interface IUserEditableFields
{
string Username {get;set;}
string Email {get;set;}
}
//... in the controller action
if(TryUpdateModel<IUserEditableFields>(user)) {
//validation passed
//only Username and Email were editable
}
This is a good resource on how to do this:
http://css.dzone.com/news/aspnet-mvc-think-before-you-bi
Are you using the strongly-type helper for the hidden field or is it exactly like you've typed. If you've got it exactly as typed, then the name of the hidden field is the value of the id, not the name of the property on the model (ID). You might want to change it to:
<%= Html.Hidden( "ID" ) %>
or (if using strongly-typed helpers)
<%= Html.HiddenFor( m => m.ID ) %>
Ben's answer is largely correct, in that a ViewModel might be more appropriate, and short of that, TryUpdateModel can be used. However, I add that in that case, rather than requiring the domain object to implement a new interface, you use the overload TryUpdateModel<T>(T, string[]), which allows you to whitelist the updateable properties in a string array by name.

ASP.NET MVC Form repopulation

I have a controller with two actions:
[AcceptVerbs("GET")]
public ActionResult Add()
{
PrepareViewDataForAddAction();
return View();
}
[AcceptVerbs("POST")]
public ActionResult Add([GigBinderAttribute]Gig gig, FormCollection formCollection)
{
if (ViewData.ModelState.IsValid)
{
GigManager.Save(gig);
return RedirectToAction("Index", gig.ID);
}
PrepareViewDataForAddAction();
return View(gig);
}
As you can see, when the form posts its data, the Add action uses a GigBinder (An implemenation of IModelBinder)
In this binder I have:
if (int.TryParse(bindingContext.HttpContext.Request.Form["StartDate.Hour"], out hour))
{
gig.StartDate.Hour = hour;
}
else
{
bindingContext.ModelState.AddModelError("Doors", "You need to tell us when the doors open");
}
The form contains a text box with id "StartDate.Hour".
As you can see above, the GigBinder tests to see that the user has typed in an integer into the textbox with id "StartDate.Hour". If not, a model error is added to the modelstate using AddModelError.
Since the gigs property gigs.StartDate.Hour is strongly typed, I cannot set its value to, for example, "TEST" if the user has typed this into the forms textbox.
Hence, I cant set the value of gigs.StartDate.Hour since the user has entered a string rather than an integer.
Since the Add Action returns the view and passes the model (return View(gig);) if the modelstate is invalid, when the form is re-displayed with validation mssages, the value "TEST" is not displayed in the textbox. Instead, it will be the default value of gig.StartDate.Hour.
How do I get round this problem? I really stuck!
I think the problem is that your ViewModel does not match closely enough with your View. It's really important in MVC that your ViewModel matches your View as closely as possible.
In your ViewModel you're assuming an integer, but in your View you're using a TextBox to render the property, which will allow any kind of text. There's a mismatch here and the difficulties you are experiencing trying to map them is a symptom of the mismatch.
I think you should either:
1. Change the type of the ViewModel property to string and then do validation in your controller to ensure the string entered is actually a number or:
2. Change the control that the View renders to a control that will only allow a number to be entered via a custom control or Javascript validation (as #Qun Wang recommends)
Personally, I'd recommend option 1. That way the ViewModel is not dependent on the View implementation.
Could you do this in your PrepareViewDataForAddAction method?..
if (!ViewData.ModelState.IsValid)
{
ViewData["StartDate.Hour"] = "Error";
}
The other fields on the form will still populate based on the properties of the Gig object.
I think you need to do some basic client side validation first.
don't allow it to post to the server.

Resources