I am using this Editor Template for Dropdownlist with ViewBag/ViewData of same property Name
#model System.String
#*
For Using this Editor Template
- There should be a viewbag/viewdata (type SelectList) of same name as of calling Model's Property
*#
#{
var modelMetadata = ViewData.ModelMetadata;
// Get property name of the model
var propertyname = modelMetadata.PropertyName;
}
#if (ViewData[propertyname] == null)
{
#Html.DropDownList(propertyname , Enumerable.Empty<SelectListItem>(), "--Select--", new { #class = "form-control" })
}
else
{
#Html.DropDownList(propertyname , null, "--Select--", new { #class = "form-control" })
}
now using it as
#Html.EditorFor(i=>i.Country,"CustomDropDown")
I also have a ViewBag.Country as SelectList of countries.
Everything works fine, but now the Naming of the Control becomes
<select class="form-control" id="Country_Country" name="Country.Country">
how to remove the additional Country from the id and name?
Additional Info:
I could have just used the #Html.DropDownList("Country") but it doesn't allow me to add the css class to the control.
I think i found the Solution.
I changed the DropDownList to DropDownListFor with some changes
#if (ViewData[propertyname] == null)
{
#Html.DropDownListFor(m=>m, Enumerable.Empty<SelectListItem>(), "--Select--", new { #class = "form-control" })
}
else
{
#Html.DropDownListFor(m => m, ViewData[propertyname] as SelectList, "--Select--", new { #class = "form-control" })
}
this auto ViewData bind is kind of confusing at times. >_<
Related
I have the following in my controller:
public ActionResult Create()
{
ViewBag.PlayerId = new SelectList(db.Players, "Id", "Name");
return View();
}
This is in the view:
<div class="form-group">
#Html.LabelFor(model => model.PlayerId, "PlayerId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("PlayerId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.PlayerId, "", new { #class = "text-danger" })
</div>
</div>
But when I submit the form, it gives me the below error:
System.InvalidOperationException: 'The ViewData item that has the key 'PlayerId' is of type 'System.Int32' but must be of type 'IEnumerable'.'
I googled a lot but were not able to find the solution. Your help is highly appreciated.
Write your #Html.DropDownList as follows:
#Html.DropDownList("PlayerId", ViewBag.PlayerId as SelectList,"Select Player", htmlAttributes: new { #class = "form-control" })
Now it will work!
You have to pass the SelectList into dropdown but actually the model binder is confused between PlayerId as viewmodel property and PlayerId as ViewBag property, hence causing the error.
Better to create a viewmodel property which will store option list with different name:
public class ViewModel
{
public int PlayerId { get; set; }
// other properties
// option list here
public List<SelectListItem> PlayerList { get; set; }
}
Then add the option lists from database into controller action:
public ActionResult Create()
{
var model = new ViewModel();
model.PlayerList = db.Players.Select(x => new SelectListItem { Text = x.Name, Value = x.Id }).ToList();
return View(model);
}
And use strongly-typed helper to bind it afterwards:
#Html.DropDownListFor(model => model.PlayerId, Model.PlayerList, "Select", new { #class = "form-control" })
Related issue:
The ViewData item that has the key is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'
i have one dropdownlist this value coming from another table so in this dropdown selected value insert into another table
see our image
<div class="col-lg-4">
<fieldset class="form-group">
#Html.LabelFor(model => model.CompanytypeID, new { #class = "form-label semibold" })
#Html.DropDownList("CompanyType", null, "--- Select CompanyType Name ---", new { #class = "select2-arrow" })
#Html.ValidationMessageFor(model => model.CompanytypeID, "", new { #style = "color:red" })
</fieldset>
</div>
public void CompanyType_Bind()
{
DataSet ds = dDSP.Get_CompanyType();
List<SelectListItem> companylist = new List<SelectListItem>();
foreach (DataRow dr in ds.Tables[0].Rows)
{
companylist.Add(new SelectListItem { Text = dr["CompanyType"].ToString(), Value = dr["CompanytypeID"].ToString() });
}
ViewBag.CompanyType = companylist;
}
public DataSet Get_CompanyType()
{
SqlCommand cmd = new SqlCommand("Select * From UserType", constr);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
return ds;
}
Error page
Your SELECT element name should match with your property name. With your current code, you are generating a select element with name "CompanyType", But in your view model(Department) your property name is CompanyTypeId.
For model binding to work, the input element name should match with the property name. So use the same name for your SELECT element and you should be good.
#Html.DropDownListFor(x=>x.CompanyTypeId, ViewBag.CompanyType as List<SelectListItem>,
"Select CompanyType", new { #class = "select2-arrow" })
Going further, do not post link to images of your code. Instead include the relevant code in the question itself.
You haven't tied your the dropdown for your code to any property of your Department model.
#Html.DropDownList("CompanyType", null, "--- Select CompanyType Name ---", new { #class = "select2-arrow" })
will generate a select element with the name CompanyType.
From your Validator code you can see that you want to tie it to CompanytypeID
Easiest thing to do would be to change you dropdown declaration to DropDownListFor and "bind" it to CompanytypeID
<div class="col-lg-4">
<fieldset class="form-group">
#Html.LabelFor(model => model.CompanytypeID, new { #class = "form-label semibold" })
#Html.DropDownListFor(m => m.CompanytypeID, ViewBag.CompanyType as IEnumerable<SelectListItem>, "--- Select CompanyType Name ---", new { #class = "select2-arrow" })
#Html.ValidationMessageFor(model => model.CompanytypeID, "", new { #style = "color:red" })
</fieldset>
</div>
It would be good to see your entire cshtml page.
I'd also recommend using ViewModels. It looks like you are POST'ing back your entity model which is why your putting this list in a ViewBag.
I am trying to add a list in search box in partial view, but I am always getting System.NullReferenceException. A similar option is working when I keep as a separate view. I am not what I am doing wrong when passing List?
Following is the snippet from views and controllers:
1] _layout.cshtml:
<div class="row">
#Html.Partial("SearchBarPartial2", Model)
</div>
2] SearchPartialView2.cshtml:
<div class="form-group">
#using (Html.BeginForm("SearchBarPartial2", "Search"))
{
#Html.LabelFor(m => m.CompanyList, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownListFor(
m => m.CompanyList,
new SelectList(Model.CompanyList, "fldt", "Value", Model.CompanyList.First().Value),
new { #class = "form-control" }
)
</div>
}
</div>
3] SearchController.cs:
public ActionResult SearchBarPartial2(cmpnytable cmpnytable1)
{
List<Company> objcompany = new List<Company>();
objcompany = GetCompanyList();
SelectList objlistofcompanytobind = new SelectList(objcompany, "ID", "Name", 0);
cmpnytable1.CompanyList = objlistofcompanytobind;
return View(cmpnytable1);
}
Your drop down list declaration already shown evidence of the error:
#Html.DropDownListFor(m => m.CompanyList, new SelectList(Model.CompanyList, "fldt", "Value", Model.CompanyList.First().Value), new { #class = "form-control" })
As Stephen said, you're assigned the model binding expression pointed to CompanyList, which becomes the source of all option tags to be rendered. It has no sense to pass the SelectList items as both binding target and source of the option list.
To resolve this issue, place additional model property with integer/string type for holding DropDownList selection result as this:
// Model
public class cmpnytable
{
// other properties here
public int SelectedId { get; set; }
}
// View
#model myproj.Models.cmpnytable
#Html.DropDownListFor(m => m.SelectedId, Model.CompanyList, new { #class = "form-control" })
Since CompanyList itself passed to view as SelectList, it's no use to create new instance of SelectList on the view.
Currently i have this field on a form:
#Html.EditorFor(model => model.AmountDecimal,
new { htmlAttributes = new { #class = "form-control" } })
But:
a) i want it to have the value "100" predefined
b) don't want it to be editable
I know how to do it in raw HTML but i need it to be in razor.
Thanks
It would make sense to set this value e.g. in the constructor of your model or in the controller before you call your view
public ActionResult MyAction()
{
var model = new MyViewModel
{
AmountDecimal= 100
};
return View(model);
}
But if you really like to do it in razor, you may use HiddenFor
#Html.HiddenFor(model => model.AmountDecimal, new { #Value = "100" });
<input type="text" name = "dummy" class="form-control" value="100" readonly/>
Keep in mind to never trust a user input ;)
I think your are loooking for something like this:
#Html.EditorFor(model => model.AmountDecimal,
new { htmlAttributes = new { #class = "form-control", #Value = "100", #readonly = "readonly"} })
I am filling out a form, however when selecting an option from the drop down list and click submit, no matter what option I select, it always parses the top one through. The displayed value never changes, so it you leave it as the default option 'please select...' and click submit, this stays as 'please select...' but the entry in the database is always the one that appears at the top of the drop down.
Here is the model:
public enum Medium
{
[Description("Teleconference & Report")]
Teleconference_Report,
[Description("Email & Telephone")]
Email_Telephone
}
[Required]
[Display(Name = "Medium")]
public Medium Medium { get; set; }
Here is the field in the form:
<div class="form-group">
#Html.LabelFor(model => model.Medium, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.DropDownList("MediumID", null, "Please select...", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Medium, "", new { #class = "text-danger" })
</div>
</div>
The "MediumID" DropDownList is populated using a viewbag which is set to whatever the following returns:
// Puts all of the mediums of communication into a user friendly dropdownlist.
public List<SelectListItem> GetMediumList()
{
List<SelectListItem> mediumList = new List<SelectListItem>();
foreach (Medium state in EnumToList<Medium>())
{
mediumList.Add(new SelectListItem
{
Text = GetEnumDescription(state),
Value = state.ToString(),
});
}
return mediumList;
}
Below shows the form section for another enum called 'Frequency', but these are not changed to user friendly strings (and is working fine).
<div class="form-group">
#Html.LabelFor(model => model.Frequency, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.EnumDropDownListFor(model => model.Frequency, "Please select...", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Frequency, "", new { #class = "text-danger" })
</div>
</div>
Below here, shows the two methods which turn the enums into user friendly strings:
// Returns a 'user friendly', readable version of the enum.
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
// Puts all of the same enums into a list.
public static IEnumerable<T> EnumToList<T>()
{
Type enumType = typeof(T);
// Can't use generic type constraints on value types,
// so have to do check like this.
if (enumType.BaseType != typeof(Enum))
throw new ArgumentException("T must be of type System.Enum");
Array enumValArray = Enum.GetValues(enumType);
List<T> enumValList = new List<T>(enumValArray.Length);
foreach (int val in enumValArray)
{
enumValList.Add((T)Enum.Parse(enumType, val.ToString()));
}
return enumValList;
}
Finally, here is the method signature where the fields are binded/bound:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Point,ApplicationID,MediumID,Frequency,StartDate,EndDate")] TouchPoint touchPoint)
Within this method, the dropdown is passed to the view using the following:
ViewBag.MediumID = GetMediumList();
Any help is greatly appreciated.
Your model has a property named Medium but your view does not bind to that property. The name of the <select> your generating is MediumID which does not exist in your model, so the default value for Medium when you submit will Teleconference_Report (the first enum value).
Change the view to
#Html.DropDownListFor(m => m.Medium, (IEnumerable<SelectListItem>)ViewBag.MediumID, "Please select...", new { #class = "form-control" })
although I would recommend changing the ViewBag property name to say MediumList to make it more obvious that its a collection. And even better, use a view model with a property public IEnumerable<SelectListItem> MediumList { get; set; } so that the viewcan be #Html.DropDownListFor(m => m.Medium, Model.MediumList, .... ).
You also need to change the [Bind] attribute to include "Medium" (and remove "MediumID") although using a view model means the [Bind] attribute is not required.
Side note: You do not need the [Required] attribute unless you want to add a specific error message using the ErrorMessage = "..." property (an enum is always required by default unless you make the property nullable).