Razor syntax for DropDownListFor - asp.net-mvc

How can I write code below with a HTML helper?
<select name="CountryId">
#foreach (var c in ViewBag.Counties) {
<option value="#c.Id">#c.Name</option>
}
</select>
This code above will give the right html code in my browser. But if I use the HTML helper below the value attribute from the option tags are missing.
#Html.DropDownListFor(
model => model.CountryId,
new SelectList(ViewBag.Countries, "Name"),
new { htmlAttributes = new { #class = "form-control" } }
)
What's wrong in this code if you know that ViewBag.Counties is an object from type List<Country> and has the properties Name (type of string) and CounrtyId (type of int).

Try this.your selectlist item class should be created in the parent class that is model class you are binding in the view page.
#Html.DropDownListFor(model => model.CountryId,new SelectList(ViewBag.Countries,"CountryID", "CountryName"),new {#class='form-control'})

Related

Custom EditorFor Template and htmlAttributes

I'm trying to use EditorFor custom templates.
I want to create a Int32 and decimal templates to render the inputs with some validations.
This is what I'm trying
#model int?
#Html.TextBoxFor(model => model, null, new { #type="text", #oninput = "this.value=this.value.replace(/[^0-9]/g,'')" } )
And I call it like
#Html.EditorFor(x => x.ExampleIntField)
It renders an <input type="text", oninput="this.value=this.value.replace(/[^0-9]/g,'')"
To here everything works, but when I try to pass extra htmlAttributes like readonly I don't understand how I must receive it in EditorFor template.
Example
#Html.EditorFor(x => x.ExampleIntField, new { htmlAttributes = new { #readonly = "readonly" } } )
I tried this I got the exact same <input type="text", oninput="this.value=this.value.replace(/[^0-9]/g,'')" rendered without readonly attribute
You are using the overload of EditorFor() that passes the object as additionalViewData. You can read that within the template from the ViewDataDictionary
#model int?
#{ var attributes = ViewData["htmlAttributes"]; } // returns { #readonly = "readonly" }
which you could then merge with your existing attributes and use in the TextBoxFor() method.
#{
var htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(attributes);
htmlAttributes.Add("oninput", "this.value=this.value.replace(/[^0-9]/g,'')";
}
#Html.TextBoxFor(model => model, htmlAttributes)
Note that TextBoxFor() generates type="text" so there is no need to add it again. In addition, you do not need the leading # unless its a reserved keyword (for example #class = "...")

#Html.DropDownList unable to add form-control class

I need to add a class to a DropDownList so it looks more presentable. Therefore, I'm using the code below with htmlAttribute:
#Html.DropDownList("DepartmentId", "Select a Department:", htmlAttributes: new { #class = "form-control" })
I'm getting errors because it says:
does not contain a definition for 'DropDownList' and the best extension method overload 'System.Web.Mvc.Html.SelectExtensions.DropDownList(System.Web.Mvc.HtmlHelper, string, System.Collections.Generic.IEnumerable<System.Web.Mvc.SelectListItem>, string)' has some invalid arguments
Can someone teach me how to add form-control class to do DropDownList?
Code that is working:
#Html.DropDownList("DepartmentId", null, htmlAttributes: new { #class = "form-control" })
There is no overload of DropDownList that lets you specify both a default option as well as HTML attributes. DropDownListFor does, however.
How are you populating your dropdown list with options? If you are doing it server-side in your controller action, you can (and probably should) use DropDownListFor:
#model DepartmentViewModel
...
#Html.DropDownListFor(model => model.DepartmentId, Model.Departments, "Select a Department:", new { #class = "form-control" })
Your view model class would be like:
public class DepartmentViewModel {
...
public int DepartmentId { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
...
}
And in your controller action:
public ActionResult Index() {
...
var model = new DepartmentViewModel();
model.Departments = new List<SelectListItem> {
new SelectListItem { Value = "1", Text = "First Department"},
new SelectListItem { Value = "2", Text = "Second Department"}
};
...
return View(model);
}
But if you're populating the dropdown list with values via javascript/jquery, it would be just as easy to use regular HTML syntax:
<select name="DepartmentId" id="DepartmentId" class="form-control">
<option value="">Select a Department:</option>
<select>

Custom editor template for Enum - How to handle null in Create view?

I am trying to create a custom editor template for enum properties.
I thought I had it good. Rob Lyndon helped me with a htmlHelper extension and it worked great on the Edit view.
But on the Create view it errors out because the value is null.
If I make the model nullable Enum? then I won't be able to get the values to populate the select list.
I don't want to have to initialize all models with a default value. And I would like to avoid having to create a different editor template for each type of enum.
Are there any better alternatives?
HtmlHelper
public static MvcHtmlString EnumTextDropDownListFor<TModel>(this HtmlHelper<TModel> html, Expression<Func<TModel, Enum>> expression, Type enumType, object htmlAttributes)
{
var enumValues = Enum.GetValues(enumType).OfType<Enum>().Select(v => v.ToString()).ToArray();
var selectList = new SelectList(enumValues.Select(v => new SelectListItem { Text = v, Value = v }));
return html.DropDownListFor(expression, selectList, htmlAttributes);
}
Editor Template
#model Enum
#{
var htmlAttributesFromView = ViewData["htmlAttributes"] ?? new { };
var htmlAttributes = Html.MergeHtmlAttributes(htmlAttributesFromView, new { #class = "form-control" });
var type = Model.GetType();
}
<div class="form-group">
#Html.LabelFor(model => model, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-8">
#Html.EnumTextDropDownListFor(model => model, type, htmlAttributes)
#Html.ValidationMessageFor(model => model)
</div>
<a class="infoonclick col-md-1" title="#Html.DisplayNameFor(model => model)" data-content="#Html.DescriptionFor(model => model)">
<span class="fa fa-info-circle"></span>
</a>
</div>
I use
#model Enum
#Html.EnumDropDownListFor(model => model, new { #class = "form-control" })
in my Enum.cshtml view
It might be a bit late, but I just came across this problem and this is how I solved it:
#{
var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType)
?? ViewData.ModelMetadata.ModelType;
}
This will allow the model to be null and avoid the nullref error you would otherwise get trying to query the type of the "null" model.
in latest dotnet core just use the following:
1- make the model dynamic
#model dynamic
2- get the enum type with:
var enumType = ViewData.ModelMetadata.UnderlyingOrModelType;
this will handle both nullable and non-nullable enums

DropDownList Error in MVC3

After adding the class to the html.dropdownlist am facing the below error.
Error:'System.Web.Mvc.HtmlHelper' does not contain a definition for 'DropDownList' and the best extension method overload 'System.Web.Mvc.Html.SelectExtensions.DropDownList(System.Web.Mvc.HtmlHelper, string, string)' has some invalid arguments
<li>
#Html.LabelFor(m => m.BuildType)
#Html.DropDownList("BuildType", new { #class = "BuildType" })
#Html.ValidationMessageFor(m => m.BuildType)
</li>
<li>#Html.LabelFor(m => m.BuildMode)
#Html.DropDownList("BuildMode", new { #class = "BuildMode" })
#Html.ValidationMessageFor(m => m.BuildMode) </li>
<li>
Where are your list options? You need to provide a list of options via an IEnumerable<SelectListItem> object (see this overload).
So your model would have something like this:
public IEnumerable<SelectListItem> BuildModeOptions { get; set; }
And your view would pass the list into the helper:
#Html.DropDownList("BuildMode", Model.BuildModeOptions, new { #class = "BuildType" })
Or, since you're using the type-safe For versions on your other helpers, use DropDownListFor on this one as well:
#Html.DropDownListFor(m => m.BuildMode, Model.BuildModeOptions, new { #class = "BuildType" })
But keep in mind, Model.BuildMode is your selected value -- Model.BuildModeOptions is for your dropdown options.
You can use:
#Html.DropDownListFor(m => m.BuildType, (SelectList)Viewbag.YourSelectList, "Select Build type", new { #class = "BuildType" })
or
#Html.DropDownListFor(m => m.BuildType, Model.YourSelectList, "Select Build type", new { #class = "BuildType" })
When you use #Html.DropDownList, you specify a name for the dropdownlist... but you are missing the SelectList itself. I think that out of the box, the helper will try to use the name of the DropDownList (in your case "BuildType") to search in the ViewData collection for the SelectList.
When you use a #Html.DropDownListFor you don't use a name, but a lamda expression m => m.BuildType that will help you in same cases to not have harcoded names.
Your SelectList (the second parameter) can be grabbed from Viewbag or from a property in your Model.
The second parameter should be the list of items you want to show in the dropdown.
so It will look like :
#Html.DropDownListFor("BuildType", m.yourListofItems, new { #class = "BuildType" })

MVC4 SelectList not selected default object

My select list isn't selecting the default object being brought in through code.
I first create my SelectList like so:
public SelectList CreateSelectList(object objSelected = null)
{
return new SelectList(GetAll().OrderBy(s => s.NumericalValue), "PeriodID", "Name", objSelected);
}
My objSelected gets filled with a Guid that's associated with the PeriodID.
Inside my controller I define my viewbag variable to the new select list.
public ActionResult Edit(Guid id)
{
Classroom classroom = classroomRepository.GetByID(id);
ViewBag.PeriodID = periodRepository.CreateSelectList(classroom.PeriodID);
return View(classroom);
}
Then in my View here's how I'm displaying my SelectList:
<div class="control-group">
#Html.LabelFor(model => model.PeriodID, "Period", new { #class = "control-label" })
<div class="controls">
#Html.DropDownListFor(model => model.PeriodID, ViewBag.PeriodID as SelectList, String.Empty, new { #class = "span3" })
#Html.ValidationMessageFor(model => model.PeriodID)
</div>
</div>
You have two problems here. First, this:
#Html.DropDownListFor(model => model.PeriodID, ViewBag.PeriodID as SelectList,
String.Empty, new { #class = "span3" })
Change ViewBag.PeriodID to ViewBag.Periods or ViewBag.PeriodList. This is confusing, and there are a number of situations in which MVC will get confused if you use the same named object. It's just best to make sure everything is named differently.
Second, The SelectList class ignores the selecteditem member of the SelectListItem. It's not used at all. DropDownListFor will take the value of model.PeriodID and make it the selected value. However, I see in your code that those should be the same so I'm guessing the naming may be a factor here.

Resources