I use pure html since I do not like the #Html class.
How do I get the value from an option in a select input ?
The model binder gives me the text property of an option and not the value, as I would have liked :)
Do I really have to use Request.From[""] to do it ?
Thanks!
EDIT
This will make the text attribute, not the value attribute, appear in the viewmodel
public ActionResult UpdateCard( UpdateCreditCardViewModel form )...
And if I just add another parameter with the input name, then the viewmodel is correcly populated. I don't have to do anything else it seems.
public ActionResult UpdateCard( UpdateCreditCardViewModel form, string Country )...
I guess that's the default behaviour ?
Related
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.
I have an editor template called String that has the following html:
<input type="text" name="#ViewData.ModelMetadata.PropertyName"
value="#(Model != null ? Model : string.empty)" style="width: 200px" />
For some reason, the properties of data type String on my view model are null when I post back if I leave the text boxes unfilled. The way i set up this editor template, shouldn't those values be empty strings instead? I'm curious why this doesn't work.
I am thinking my only other alternative is to create my own custom model binder that will automatically convert all my null values to string.empty for data type "String".
Any advice?
The way i set up this editor template, shouldn't those values be empty strings instead?
Nope.
I'm curious why this doesn't work.
The HTTP Protocol knows nothing about the difference between String.Empty and null (it's language agnostic, ie what would Perl, PHP, Java, Phyton do?). All values are passed as strings, so there is no concept of null. The default ModelBinder simply returns null because it is more pragmatic then String.Empty (that is to say, more often than not, null represents in the context of parameters, no value was passed).
how to get MVC model binder to return empty string instead of null with razor editor template?
Not possible in terms of a razor-editor. Remember HTTP is agnostic, so you have lots of choices; custom ModelBinder, Hidden fields that specify a value via Javascript/jQuery Input detection, modifying the values during Validation (IValidateObject), etc.
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.
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)
I have a database first design. I want to have default values for my model so that a user can just leave an editor textbox blank for one of my nullable fields. EF doesn't seem to want to just throw null into the database, so I was hoping I could set default values to null for my nullable attributes.
Ie I want to insert null into my database for an attribute if the textbox is left blank when submitted.
I've read you can add a contructor to a partial class to do what I want. So you would basically have:
public partial class MyClass{
public MyClass()
{
field1 = null; //this would be the default value for field1
}
}
The only problem is the autogenerated partial class for the model I'm working on already has a constructor, so I can't add a constructor to a different (permanent) partial class. I don't want to update the autogenerated partial class because it will just be overwritten when I update my edmx from the database.
The default value of the string should already be null, so I think you are taking the wrong path.
The problem is a textbox will always be passed with a form post, even if it is blank, which will result in an empty string in your controller rather than a null value, even if you find a way to explicitly set your string to null in your initial class.
Instead, check the value of the string in your controller after the form is posted back, and if it is empty, set it to null.
if (String.IsNullOrEmpty(formModel.MyString)) formModel.MyString = null;
Either that, or create a default model binder to check the value of the field during model binding, and not set it if it is empty.