Retain DropDownList Value asp.net MVC [duplicate] - c#

I am working on an ASP.NET MVC-4 web application. I'm defining the following inside my action method to build a SelectList:
ViewBag.CustomerID = new SelectList(db.CustomerSyncs, "CustomerID", "Name");
Then I am rendering my DropDownListFor as follow inside my View:
#Html.DropDownListFor(model => model.CustomerID, (SelectList)ViewBag.CustomerID, "please select")
As shown I am naming the ViewBag property to be equal to the Model property name which is CustomerID. From my own testing, defining the same name didn't cause any problem or conflict but should I avoid this ?

You should not use the same name for the model property and the ViewBag property (and ideally you should not be using ViewBag at all, but rather a view model with a IEnumerable<SelectListItem> property).
When using #Html.DropDownListFor(m => m.CustomerId, ....) the first "Please Select" option will always be selected even if the value of the model property has been set and matches one of the options. The reason is that the method first generates a new IEnumerable<SelectListItem> based on the one you have supplied in order to set the value of the Selected property. In order to set the Selected property, it reads the value of CustomerID from ViewData, and the first one it finds is "IEnumerable<SelectListItem>" (not the value of the model property) and cannot match that string with any of your options, so the first option is selected (because something has to be).
When using #Html.DropDownList("CustomerId", ....), no data-val-* attributes will be generated and you will not get any client side validation
Refer this DotNetFiddle showing a comparison of possible use cases. Only by using different names for the model property and the ViewBag property will it all work correctly.

There is not harm to use it. You will not get any error. but best practice is to bind model property.

Related

ASP.NET MVC : DropDownList to model field

My model is a rpg character. He has a field "Game", that is a strongly types object containing "Careers" fields, themselves strongly types object.
Model must choose a career amidst multiple choices.
I currently display it as is :
#Html.DropDownListFor(model => model.career,
new SelectList(Model.game.professions, "name", "name"),
)
(where professions is of type List[career]).
However, this does not bind the selected value of the dropdownlist to the career field of my character.
Any hint? I've been searching for a while, but I only find way to populate a dropdownlist from a model, and nothing on how to ensure the selected value is passed back to the model.
Thank you
Edit = I accepted RedGoodBreaker's answer even though it wasn't what I expected because it helped me find the solution.
Point is : you can't select an object via DDL in mvc, you can only select a basic type that references to that object (in my case, I chose the string field "name" of my career).
#Html.DropDownListFor generates html like
<select id="CarType" name="CarType">
<option value="a">Volvo</option>
<option value="b">Saab</option>
<option value="c">Mercedes</option>
<option value="d">Audi</option>
</select>
so as you can see they are simple strings(in your case both value and text are the same). when you select one posting form will produce something like that:
...
CarType="a"
...
You can do several tricks but question is it worth doing it and do you really need it.
Normally your model should have field CarrerName and dropdownlist should be bound to it. In Controller Action which accepts form submission you should rehydrate Carrer from database or other store using CarrerName (this is why we asked about id).
I understand that Skills are some kind of dictionary that does not change much. Options for storing are(there maybe some others that i am not aware):
save your dictionary to Session before presenting form or better after logon if this dictionary does not change. You can access it after form submission and find apropriate key (best int or guid)
System.Web.Caching.Cache.
TempData.
Database.
this options have its cons and pros about which you must read because i don't know your application specification.
If you need this data before submission in view or javascript you have to do it yourself ( there is no simple one-liner). I can help but i dont know what do you want to achieve.
Your career object should have Id field and you need to pass it to DropDownListFor
Please refer the below link
MVC DropDownList
and then in the Razor view
#Html.DropDownListFor(m => model.career, new SelectList(Model.game.professions, "Value", "Text"), "Career")
Of course the model needs to be passed into the view with the values in the List already populated

boolean model propertie's values not bind in POST method

I have table record as follows
this how those two properties defined in model classes
public bool? Report_Users { get; set; }
public bool? Innovation_Discussion_User { get; set; }
this is Form syntax that used to populate Boolean values in checkboxes
#Html.CheckBox("Report User", Model.Report_Users.GetValueOrDefault(), new { #value = "false" }) Report User
#Html.CheckBox("Innovation Discussion User", Model.Innovation_Discussion_User.GetValueOrDefault(), new { #value = "false" }) Innovation Discussion User
This is check boxes view of that form
but once I submit , I can see in model those two properties values getting null in POST method
How can I bind this check-boxes values to Boolean property fields, properly ?
There a a number of issues with you implementation.
Your CheckBox("Report User", ...) method is generating a checkbox (and associated hidden input) with name="Report" and your model does not contain a property named Report. Because no value is posted back for Report_Users, its value will always be its default (null) in the POST method. In order to bind to bool? Report_Users then it would need to be CheckBox("Report_User", ...) (underscore not space).
Changing that however means the value of Report_User now always be false instead of null because you have added new { #value = "false" }. The CheckBox() method generates 2 inputs, <input type="checkbox".. value="True" /> and <input type="hidden".. value="False" /> in order to correctly bind to your property. You have now overridden it to generate <input type="checkbox".. value="false" /> so a value of false is posted even if the checkbox is checked.
But the real issue with your code is that your property is bool? (nullable) and CheckBox() is designed to bind to bool. typeof bool? has 3 states (true/false/null) whereas a checkbox has 2 states (on/off or true/false). Its not clear why your database property is nullable, but if you cannot change it, then (as always), use a view model with a bool property. In the GET method, when mapping your data model to the view model, you can use
myViewModel.ReportUser = myDataModel.Report_User.GetValueOrDefault();
and now you can build you view correctly using the strongly typed helper
#Html.CheckBoxFor(m => m.ReportUser)
#Html.LabelFor(m => m.ReportUser, "Report User") // use a label
// or add [Display(Name="Report User")] and use #Html.LabelFor(m => m.ReportUser)
What to learn from this:
If your model is not binding, always check the html your generating
(the name attributes of the form controls must match the name of
the property)
Always use the strongly typed xxxxFor() HtmlHelpers to generate
form controls. Not only do you get intellisense, it ensures that the
correct name attributes are generated, and any errors are reported
Never attempt to change the value attribute when using the
HtmlHelpers (or the name attribute). The helpers generate the
correct html based on the model property and changing them from the
default values will only lead to model binding failing

How to make Html.TextBox(string name) render sanitized input?

I am using ASP.NET MVC4 with .NET Framework 4.5. I have a controller action that accepts a model of one type with a property named 'Name' but renders a view using a model of another type. I am still able to use #Html.TextBox("Name") and #Html.ValidationMessage("Name").
I want the textbox to display the sanitized input, that is, the input without leading/trailing/extra spaces the user may have entered. The setter for my model sanitizes the value for me, and I am successfully obtaining the sanitized value using the getter within the controller action. It's just that upon submitting the form, the textbox still displays the unclean input.
Is there some mechanism I am missing? Is the #Html.TextBox(string name) helper looking at the raw request data and not the model? If so, how come the validation message is working?
Update
I have just tried defining a new view model that includes my textbox field so I could hopefully just use the #Html.TextBoxFor helper. Everything is still working as it was after a re-build, I am still not getting sanitized input appearing in the textbox. I still don't know a solution for this.
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult MyAction(MyViewModel model)
{
if (this.ModelState.IsValid)
{
using (var service = new MyService())
{
model.MyResults = service.DoSomething(model.MySanitizedProperty);
}
}
return this.View("MyView", model);
}
Then, in "MyView":
#Html.TextBoxFor(m => m.MySanitizedProperty)
<input type="submit" value="Go" />
#Html.ValidationMessageFor(m => m.MySanitizedProperty)
In the controller, invoking model.MySanitizedProperty returns the sanitized value while the textbox goes on to display the unsanitized data.
It sounds like a problem with the models; make sure you are properly accessing the value from the model you wish to populate it with, i.e., possibly discretely specifying the model "Name" is coming from.
Also, check to see that the setter has a chance to operate on the value - if the controller is activating before the setter function is used, then you'll only get the original input value.
Realize you have to go to the server for the setter to work, possibly you need a async postback or such, and the value reloaded.

HtmlHelper.TextBox uses the model value even when an explicit value provided

In a view I'm using this overload of HtmlHelper.TextBox:
public static MvcHtmlString TextBox(
this HtmlHelper htmlHelper,
string name,
Object value
)
The documentation states:
value
Type: System.Object
The value of the text input element. If this value is null, the value of the element is retrieved from the ViewDataDictionary object. If no value exists there, the value is retrieved from the ModelStateDictionary object.
I do provide a value when I call this overload, and this value is not null. Nevertheless, the value for the textbox is retrieved from the ModelStateDictionary whenever it is present there.
In order to force the textbox to use the value provided inline, I have to reset the model first in the controller (or remove the key with the textbox's name from the keys collection).
Same applies to other controls rendered by HtmlHelper.
Where is my understanding wrong? Or is that a bug in the documentation?
ModelState always has precedence in all input helpers, not just TextBox. This allows you to specify a default value in the view, and after POST render the posted value (taken from ModelState) without having to manually pass the posted value to the view. To use a different value you must remove the entry from ModelState.
This is how the model binder works, it takes the values from the modelstate, probably to preserve the values from a failed postback or validation failure. Have you tried using the Html attributes to set the value
Html.TextBox("Id", new { Value = Model.Id})
Si
Maybe this will help.
Using viewmodel with property below and ViewData["textboxvalue"]
public string Id { get; set; }
If you have provided an object that can be bound into the "value" parameter, the the html helper will always use its value.
-Text box value bound to view model - these show the model's id
#Html.TextBox("Id", Model.Id)
-Text box with provided value from view data - these show the view data's value
#Html.TextBox("Id", ViewData["textboxvalue"])
Even if the name provided is not the same as the property name, the value will still be that provided by the model
-Text box value bound to view model - these show the model's id
#Html.TextBox("Id2", Model.Id)
-Text box with provided value from view data - these show the view data's value
#Html.TextBox("Id2", ViewData["textboxvalue"])
If you provide your own custom
-Text box with provided hardcoded value - this shows the string provided in view
#Html.TextBox("Id", "my hardcoded value in view")
The documentation is stating - if you do not populate the "value" parameter, as in the below:
#Html.TextBox("Id", null)
Then mvc framework will automatically try and search both the model that is bound to the view and the data dictionary.
If you have this case, then
-Found a property called "Id" in view model. Text box value set to the model's value
#Html.TextBox("Id", null)
But if the "name" value is not a property/key in the model/dictionaries, then the framework could not find any value, so the text box value will be an empty string
-Text box with name that is not property in view model or view data
#Html.TextBox("Id2", null)

UpdateModel is not updating "deep" property

I have an ASP.NET MVC application. At a certain point I get a FormCollection in a Controller method that I want to use to update a model. In the collection not all of the values are properties of that model and the property to be updated is an item from a list, and that list is also an item from another list. Something like this (I hope this is clear):
propertyToUpdate --> model.Items[0].Subitems[0].SomePropertyClass.Value;
I tried this in my Controller:
UpdateModel(model);
The problem is that this is not working and I assume it has something to do with the fact that the reflection is not working. I went searching and stumbled upon this article. So I understand that using the prefix-parameter solves the problem. But not in my case, as the properties lie "deeper" in the model as items from a list.
Does anyone know how I can solve this?
Update:
Here's the EditorTemplate for the property:
#model Q95.Domain.Property
<li>
#Html.DisplayFor(p => p.Description) :
#Html.DisplayFor(p => p.Quantity.Value)
#Html.DisplayFor(p => p.Quantity.Unit.Description)
<br />
#Html.TextBoxFor(p => p.Quantity.Value)
</li>
This template is called like this:
<ul>
#Html.EditorFor(model => model.SegmentRequirement.MaterialRequirements[j].Properties)
</ul>
Is this enough code or is there something still missing?
Update2:
Ok, in all the sub-properties I defined parameterless constructors and now I call:
UpdateModel(segmentRequirement, "SegmentRequirement", form.ToValueProvider());
This updates the model, but everything from MaterialRequirements is re-instantiated... :S
UpdateModel works fine on "Deep properties".
The problem is probably the data in the collection you get isn't equal to the properties names.
Check 3 places to see the values you get from the page
The form values.
The route data
The query string
In exact that order.
The keys should match you model properties names.
Update:
How to match the keys to properties names?
The input id will be the key you will get, change the the ids to match your properties names, or even better, use the HtmlTextBoxFor helper: see this article:
Maybe you should create flattened ViewModel and then use that to populate the view, and later synchronize it with the real model.
Can you show us your model and your view, if you are not using htmlhelper, you then have to understand the naming convention very well in order to make the model binding work with your model. so the first thing in first is to show us your model and view.

Categories

Resources