ModelState.IsValid for the unnecessary field Name - asp.net-mvc

I have a very simple model. I have a location that has 2 fields, Id and Name. I have InventoryItems that has a number of scalar fields with a FK to the location at which it is stored. I have a View for creating an InventoryItem. The view has a drop down for `
<div class="editor-label">
#Html.LabelFor(model => model.Location)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Location.Id, new SelectList(ViewBag.Locations, "Id", "Name"))
</div>
The controller code checks ModelState.IsValid which is returning false because the NAME of the location in the ModelState is empty. I really only need the Id to save the InventoryItem. But I have [required] in the Location Name field because when I go to allowing the addition of Locations, I want that field required.
Can someone tell me the CORRECT way to deal with this in the MVC design pattern?

Well if the name is already set before this point you could just use a #Html.HiddenFor() to hide the name on the page it keeps the value for the HttpPost.
If this isn't the case then I suggest dropping the required requirement on the name in the model itself and use it on a View Model, this way you can have two different levels of validation, just bare in mind you need to make sure that if the field isnt populated at the point where it's needed it will error.
Personally I would use View Models whenever you have changing validation requirements

The best way to go about it is to use ViewModel that have only the fields you need on the UI side and then convert to your actual Model in the controller.
In your case, you could use a LocationLink in your View/Form that only takes an Id like:
public class LocationLink
{
[Required(ErrorMessage = "No id provided")]
public string Id { get; set; }
}
Then in your controller you load the appropriate Location from your data store with the supplied Id and add that to the parent model.
Usually you should have a ViewModel for Display with all the fields (Locationwith Id and Name) and a ViewModel for create/edit forms (LocationLink in that case with only Id).

Related

Stopping form prepopulation in MVC

In an MVC view with a form on it and given the following code using HTML helpers:
#Html.TextBoxFor(m => m.FirstName, new { id = "firstName", maxlength = "50", #class = "form-input" })
Is there a way to stop this form automatically populating the fields with data? I know it's by design and in most cases is helpful but in this case I want to be able to turn that functionality off.
To clarify - If I have a ViewModel with this property in it:
[Display(Name = "First Name")]
public string FirstName { get; set; }
I understand that the HTMLHelper TextBoxFor will allow me to use the strongly typed
m => m.FirstName
when creating the input.
That's fine. However, if I have the ViewModel populated with data then it also shows this data in the input field, this is by design and I get that.
Now, imagine you wanted the strength of the strongly typed aspect but without the automatic filling of the data.
The only option appears to be:
#Html.TextBox("myTextBox", "value goes here", new { #class = "form-control" })
Which is brittle where the name / id values are concerned. I prefer the strongly typed nature of the TextBoxFor but can't have that without also automatically showing whatever the ViewModel data is.
It sounds like you're talking about the browser behaviour here, so you want to turn off autocomplete. You can use this on a per input basis:
#Html.TextBoxFor(m => m.FirstName, new { ..., autocomplete = "off" })
Or you can do it on the whole form:
#Html.BeginForm(action, controller, FormMethod.Post, new { autocomplete="off" })
EDIT:
Reading your comments it seems you're populating the view model with the values and seeing them when you render the view. In which case, the answer is simple, reset the model before passing it to the view:
return ViewModel(new TModel());
While passing the viewmodel to view in controller you can set those properties to blank value or null for which you want empty textboxes in UI.

Confused about Usage of LabelFor() html helper in MVC 2.0

I am working on an MVC 2.0 C# web Applciation. In one of my form, i am using LabelFor() html helper.
I am using the following syntax:
<%=Html.LabelFor(model=>model.Addedon)%>
Here, for this label i would like to associate a initial value that is DateTime.Now
I tried some thing like this:
<%=Html.LabelFor(model=>model.Addedon,new{value=DateTime.Now})%>
But, i am getting an error saying that there is no over load for this helper taking two arguments.Please help
UPDATED:
The form is create form/ add form which makes an insert operation. So, i am building a model and updating that model to the database.
In that model, i have a field called createdby. So, i need to associate this value with the username logged in and doing the insert operation.
So, how to associate this username value with the model field and i need to display as label so that it will be read only field.
Hope this makes clear..
LabelFor is only for, you guessed it, rendering a <label> element.
It also uses the [Display] and [DisplayName] attributes, so you can have a strongly-typed label with custom name.
What you're after is probably this:
<div>
<%= Html.LabelFor(model => model.Addeon) %>
</div>
<div>
<%= Html.DisplayFor(model => model.Addeon) %>
</div>
So the LabelFor will generate the property name description (e.g. 'Addeon'), while the DisplayFor will render the property value. DisplayFor can use the [DisplayFormat] attribute if you need custom formatting. You can set the default property value in the view model's constructor:
public class ViewModel
{
[Display(Name = "My awesome date")]
public DateTime Addeon {get;set;}
public ViewModel()
{
Addeon = DateTime.Now;
}
}
[EDIT]
Actually, your edit would make for a good second question instead of putting it here. Anyway, in your situation I'd create a dedicated view model that would hold the properties you need (e.g. user name) and would be filled in controller. Everything else would be conceptually the same - view would bind to the view model.

ASP.NET MVC Binding to View Model as well as routed values

I know similar questions have been asked regarding complex model binding in ASP.NET MVC, but I am having a problem binding because of a lack of a sufficient prefix coming back on the POST and wondered if there were an easy solution.
I have a view Model that looks something like this:
public class ViewModel<Survey, Contact>
{
public Survey Model { get; set; }
public Contact Model2 { get; set; }
}
I then have an action method like this that accepts the POSTed
public ActionResult Survey(
string id, string id2, SurveyViewModel<Survey, Contact> model)
{
// code goes here...
}
In my form, the first two id's are from the URL route and I then have form code (using #Html.EditorFor(x => x.Model.SurveyName) or similar), generated with names like this:
<input class="text-box single-line" id="Model_Email"
name="Model.Email" type="text" value="" />
A post works if I change the name from Model.Email to model.Model.Email, but I am trying to avoid having to create a custom model binder.
Is there
A setting I can make in the view to change the name for all fields rendered in a view using the #Html.EditorFor typed view helpers?
Something I can change using the Bind attribute on the action that would allow it to default binding to that object?
The answer may be "build a custom binder", but I just wanted to pose the question before biting that off.
Thanks for the help. Best Regards,
Hal
You can pass custom viewdata with custom HtmlFieldPrefix to view. Every control rendered with helper will have that prefix.
ViewData.TemplateInfo.HtmlFieldPrefix = "prefix here";
Take a look at this: Forcing EditorFor to prefix input items on view with Class Name?

Model with List - approaches to add new item to the list from a Razor view

I have a model with various properties but the one of interest is a List of another type of Model.
For example:
public class User
{
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<UserInterest> Interests { get; set; }
}
I then use an Editor Template within my view to render out a view for each item of the model items.
#Html.EditorFor(x => x.Interests)
The EditorFor template looks something like:
#model Interest
<div>
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.InterestText)
#Html.CheckBoxFor(x => x.Delete)
....
</div>
Something very similar to the accepted answer here: Model Containing List of Models (MVC-3, Razor)
My question is - how would you from the client-side (jQuery) create a new item within the property without going back to the server. I currently have a rough way of doing it whereby I post the data back to my controller which returns the model back with a new blank item within the Interests property.
This seems to be overkill making a HTTP request and not very elegent. I was thinking of using jQuery .Clone() but not entirely sure on what I'd need to do in terms of naming the elements and clearing existing values.
So does anybody have any suggestions. I'm hoping to get more opinions and different approaches.
You can simply create the Textbox and checkbox on the fly and add that to the DOM. When saving it, Use jQuery ajax to post that data ( new record data) to an action method and save it there. Return a status back (Succcess /Falied) from your action method to your client side code ( your callback function of jQuery ajax/post) and check it there. If it is success, Show a success message to the user and append the new item to the existing list.
Sample jSFiddle : http://jsfiddle.net/carwB/2/
If you want to return some complex data ( ex : All new records with its id etc..) along with the status, you may return JSON from your action method.
EDIT : To keep your Model binding works with the newly added dynamic elements, you need to follow the naming convention of the elements.
The trick is to keep the id property value of the html element in this format.
CollectionName_ItemIndex__PropertyName
and name property value in this format
CollectionName[ItemIndex].PropertyName
I created a sample working program and explained it how it works Here based on your requirements.
In such situations I prefer to use client templating. You send data to server with ajax and then receive JsonResult. Look at JsRender this is javascript lib without jQuery dependency.
1.Create two partial view one is for list item and second one is creation
2.First partail view should be inside the div which has id 'divMdeolList'
3.and Creation view will have the code like that
#using (Ajax.BeginForm("SubmitData", new AjaxOptions { UpdateTargetId = "divMdeolList" }))
{
#Html.TextBoxFor(x => x.InterestText)
<p>
<input type="submit" value="Create" />
</p>
}
4. And then create a ActionResult type action on controller that will render the partialview
public ActionResult SubmitData(YourModel model)
{
//Do : save the record
return PartialView("FirstPartailView", model);
}
This will update the View without postback

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.

Resources