I'm building a data entry interface and have successfully bound the columns that have reference tables for their data using DropDownList so the user selects from the pre-configured values.
My problem now is that I don't want the first value to be selected by default, I need to force the user to select a value from the list to avoid errors where they didn't pick that field and by default a value was assigned.
Is there a more elegant way of doing this than to add code to include an empty value at the top of the list after I get it from the database and before i pass it to the SelectList constructor in my controller class?
The Html helper function takes a 'first empty value' parameter as the third argument.
<%=Html.DropDownList("name",dataSource,"-please select item-")%>
You can also use this way:
dropdownlist.DataTextField = ds.Tables[0].Columns[0].Caption;
dropdownlist.DataValueField = ds.Tables[0].Columns[1].Caption;
dropdownlist.DataSource = ds;
dropdownlist.DataBind();
dropdownlist.Items.Insert(0, new ListItem("Select ...", string.Empty));
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 would like to add a data-other-for attribute to a text input, to link it to a select, so that it can be used to capture a value not present in the select when the user selects 'Other' in the select. The attribute's code will determine which value or description is in fact 'Other', and if so, enable the text input and maybe make it mandatory.
It seems like the only way to do this is by creating a new helper, because going via a ValidationAttribute I can only add preset validation HTML attributes to my text input. Or go large and write a whole new metadata provider.
You could try to implement a custom ModelBinder.
Say, in the select you would have:
new SelectListItem(Text = "Other", Value="bind:propertyName", Selected = False);
Then in the overriden BindModel, you simply look for bind: in the model properties and when found, copy your value from there.
After this, you should be able to add normal validation attributes to your select list.
Problem Description:
I am using ASP.NET MVC and I have the following method in my Controller Class. This method uses SelectList method to select a list of items from the database. These items will then be passed to the view to be displayed in a drop down list.
public ActionResult Edit(int id)
{
Album album = db.Albums.Find(id);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
return View(album);
}
My Understanding of the selectMethod:
I know that the first param takes a list of items.
The third param is the property to be displayed.In this case, we will be displaying the name property of the Artists.
Based on my research, I found out that the 4th param is the default value that will be displayed on the dropdown list.
My Question:
1) I would like someone to help me understand about the second param.
2)Since we are displaying names of the artists, how can we display a default artist name in the fourth param using Artist ID?
I hope you guys understood my questions. I would be happy to clarify them to you if you need me to do so.
The second parameter is the name of the "value" property or field on each element in the first parameter. Since two artists could conceivably have the same, it's generally better to use an ID column (as in the example) so that you know specifically which item was selected.
In the example, you are providing the artist of the currently-viewed album as the default to appear. Assuming that db.Artists includes an artist whose ArtistId property matches the given value, the rendered HTML will produce a select list where that artist is selected.
Did that answer your questions?
Per the documentation:
The first parameter is an IEnumerable of objects from which to construct the list.
The second parameter is the name of the object property (for each object in the list) to be used as the value attribute of each rendered HTML <option> element.
The third parameter is the name of the object property (for each object in the list) to be used as the text attribute of each rendered HTML <option>.
The fourth parameter is the default selected value (which indicates the element of the list that will be rendered with the selected attribute).
I have a system.web.mvc.selectlist when I use .selectedvalue it gives me the value as expected however I use an int ID as the value and would like to get the display text instead.
Update
I've created a selectlist and I'd like to retrieve the selected text on the next line of code. I.e.
SelectList sl = new SelectList(items, "id", "name", 10);
String txt= sl.selectedvalue.text;
That last line is where I am stuck. I'm looking to get the name field for the item with id 10. Ideally without looking up in the db as I want a generic function I can use on all select lists.
I don't think this is possible since the text isn't passed back to the server in a post, only the value is. I can think of two ways to get it though:
Query the database with the value to get the text.
Set the text in a hidden field on the client side before posting the
form. You can do this with jQuery for example.
Short: how does modelbinding pass objects from view to controller?
Long:
First, based on the parameters given by the user through a search form, some objects are retrieved from the database.
These objects are given meta data that are visible(but not defining) to the customer (e.g: naming and pricing of the objects differ from region to region).
Later on in the site, the user can click links that should show details of these objects.
Because these meta data are important for displaying, but not defining, I need to get the previously altered object back in the controller.
When I use the default asp.net mvc modelbinding, the .ToString() method is used. This off course doesn't return a relevant string for recreating the complete object.
I would have figured the ISerializable interface would be involved, but this is not so.
How should I go about to get the desired effect? I can't imagine I'm the first one to be faced with this question, so I guess I'm missing something somewhere...
The default model binding takes form parameters by name and matches them up with the properties of the type specified in the argument list. For example, your model has properties "Price" and "Name", then the form would need to contain inputs with ids/names "Price" and "Name" (I suspect it does a case insensitive match). The binder uses reflection to convert the form values associated with these keys into the appropriate type and assigns it to the properties of a newly created object of the type specified by the parameter (again derived by reflection).
You can actually look at (and download) the source for this at http://www.codeplex.com/aspnet, although you'll have to drill down into the MVC source from there. I'd give a link to the DefaultModelBinder source, but the way they are constructed, I believe the link changes as revisions are introduced.
So, to answer your question, you need to have parameters (could be hidden) on your form that correspond to the properties of the object that you want to recreate. When you POST the form (in the view) to the controller, the binder should reconstitute an object of the specified type using the form parameters. If you need to do translation from the values in the form parameter to the object properties, you'll probably need to implement your own custom model binder.
[EDIT] In response to your second post:
Let's say that we want to have a link back to an action that uses a customized object. We can store the customized object in TempData (or the Session if we need it to last more through more than one postback) with a particular key. We can then construct the action link and provide the key of the object as value to the ActionLink in an anonymous class. This will pass back the key as a Request parameter. In our action we can use the key from this parameter to retrieve the object from TempData.
<%= Html.ActionLink( ViewData["CustomObject1",
"Select",
new { TempDataKey = ViewData["CustomObject1_Key"] }
) %>
public ActionResult Select()
{
Entity custObj = null;
string objKey = Request.Params["TempDataKey"];
if (!string.IsNullOrEmpty(objKey))
{
custObj = (Entity)TempData[objKey];
}
... continue processing
}
#tvanfosson
Thanks for your explanation, but what about links? (no forms involved)
Currently the Html.ActionLink(c=>c.Action(parameter), "label") takes objects as parameter. These have to be translated into URL parts. For this, MVC ALWAYS goes to the .ToString() method. I don't want to serialize my object in the ToString method.
Shouldn't I be able to somehow help the framework serialize my object? Say through the ISerialize interface or something?