Create DropDownListFor from SelectList with default value - c#

I have a dropdownlistfor:
#Html.DropDownListFor(model => model.Item.Item.Status, new SelectList(#Model.AllStatus, "id", "Description"), new { id = "statusDropdown" })
#Html.ValidationMessageFor(model => model.Item.Item.Status)
HTML output:
<select id="statusDropdown" class="valid" name="Item.Item.Status" data-val-required="The Status field is required." data-val-number="The field Status must be a number." data-val="true">
<option value="2">Completed by Admin</option>
<option value="3">General Error</option>
<option value="4">New</option>
</select>
How can I update this code to set a default selected option? E.G.
<option value="4" selected>New</option>
I tried:
#Html.DropDownListFor(model => model.Item.Item.Status, new SelectList(#Model.AllStatus, "id", "Description",#Model.SelectedStatusIndex), new { id = "statusDropdown" })
#Model.SelectedStatusIndex has a value of 4, but does not change the default option to New.
I also tried:
#Html.DropDownListFor(model => model.SelectedStatusIndex, new SelectList(#Model.AllStatus, "id", "Description"), new { id = "statusDropdown" })
#Html.ValidationMessageFor(model => model.Item.Item.Status)
This selects the default option "New", but model.Item.Item.Status is not set by the dropdown on HTTP POST.
Other Detail:
model.Item.Item.Status is an int. #Model.AllStatus is a SQL table that lists all available status options.

There exist already some discussions about that here or there. One of the problems might be using a different type than string for the key value. I had similar problems in past and I know that i solved it like this - explicitly setting the Selected property when preparing the list (in your case, AlLStatus).
Would mean, for your case (in controller action):
IEnumerable<SelectListItem> selectList =
from s in allStatus // where ever you get this from, database etc.
select new SelectListItem
{
Selected = (s.id == model.Item.Item.Status),
Text = cs.Description,
Value = s.id.ToString()
};
model.AllStatus = selectList;

This is in addition to the answers above. This is how I would have done it.
The view model is there to represent your data. So for a single drop down list I would have the following:
public class MyViewModel
{
public int StatusId { get; set; }
public IEnumerable<Status> Statuses { get; set; }
}
And the Status class would look like this:
public class Status
{
public int Id { get; set; }
public string Description { get; set; }
}
The controller's action method to handle the view:
public class MyController
{
private readonly IStatusService statusService;
public MyController(IStatusService statusService)
{
this.statusService = statusService;
}
public ActionResult MyActionMethod()
{
MyViewModel viewModel = new MyViewModel
{
Statuses = statusService.GetAll(),
StatusId = 4 // Set the default value
};
return View(viewModel);
}
}
The view will look like this:
#model MyProject.ViewModels.MyViewModel
#Html.DropDownListFor(
x => x.StatusId,
new SelectList(Model.Statuses, "Id", "Description", Model.StatusId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.StatusId)
There you go.

I ended up using a variant of thomasjaworski's answer.
View:
#Html.DropDownListFor(model => model.SelectedStatusIndex, new SelectList(#Model.StatusSelectList, "Value", "Text"), new { id = "statusDropdown" })
ViewModel constructor
StatusSelectList = AllStatus.Select(x =>
new StatusSelectListItem
{
Text = x.Description,
Value = x.id.ToString()
}).ToList();
this.SelectedStatusIndex = 2;//Default Status is New
Controller on HTTP POST
I set model.Item.Item.Status seperately from the dropdown itself:
model.Item.Item.Status = model.SelectedStatusIndex;
because the dropdown set's the value of the expression passed as the first argument:
#Html.DropDownListFor(model => model.SelectedStatusIndex, new SelectList(#Model.StatusSelectList, "Value", "Text"), new { id = "statusDropdown" })
In this case model.SelectedStatusIndex is what is set by the dropdown. This controller implementation is what I found to be tricky.

You can use "Insert" for adding default value of Dropdown and add it to your Dynamic list :
By this way you don't need to use Razor in your View.
List<Y> m = X.GetList();
m.Insert(0, new Y{ Name = "--Select--" });

SelectList ProductSizeList = new SelectList(_context.Sizes, "SizeId", "SizeName");
//after you create the selectList you have to create the default select list item
SelectListItem AllSize = new SelectListItem("All Size", "0");
// and after this you add this item to the begin of the selectlist
ViewData["SizeId"] = ProductSizeList.Prepend(AllSize);

I assign DropDownListFor's expression with value which is already defined in List. It works for me. I use List<SelectListItem> Model.IncidentPriorityList for ddwn's selectlist.
Model.incident.INCIDENT_PRIORITY_ID = Model.DefaultParameterId;
#Html.DropDownListFor(m => m.incident.INCIDENT_PRIORITY_ID, Model.IncidentPriorityList, "Select", new { #class = "form-control selectpicker", id = "drpPriority", #required = true })

Related

.NET 6 - Set SelectListItem to Selected?

I have a DropDownList which I populate like below:
Controller
IEnumerable<Category> categories = _db.Category.ToList();
var selectList = _db.Category.Select(i => new SelectListItem()
{
Text = i.Name,
Value = i.Id.ToString()
});
ViewBag.categoriesSelectList = selectList;
And use in view like so:
<select asp-for="Category" name="categoryID" asp-items="#ViewBag.categoriesSelectList" class="form-control">
<option>Vælg Kategori:</option>
</select>
However, I can't seem to figure out how I can set the already selected value, so the dropdown "starts" on that value. I tried enumerating over the selectList and changing the Selected attribute of the SelectListItem, but it doesn't work since it won't save the changes I make.
Hope my question makes sense :) thanks all.
Option 1:
Modify your code to include Selected property when creating list of SelectListItem items:
var selectList = _db.Category.Select(i => new SelectListItem()
{
Text = i.Name,
Value = i.Id.ToString(),
Selected = /* Some condition that is true when the current item should be selected */
});
Option 2:
Define a view model with structure that might be referenced in the <select> tag:
public class SelectViewModel
{
public string Category { get; set; }
public List<SelectListItem> Categories { get; set; }
}
The action method:
public IActionResult Categories()
{
var model = new SelectViewModel() ;
model.Categories = _db.Category.Select(i => new SelectListItem()
{
Text = i.Name,
Value = i.Id.ToString()
});
model.Category = ... your_code_to_set_default_selection;
return View(model);
}
The view:
#model SelectViewModel
<select asp-for="Category" asp-items="#Model.Categories"></select>
Can find some mode information in the documentation: The Select Tag Helper

How do I get the correct radio button selected using MVC RadioButtonFor with float values?

I have an editor template Duration that holds four simple radio buttons.
I am using this template for a property on my class Test.
I cannot get this property to bind to the radio button list and select the correct radio button on load. Selecting a value and submitting will return the correct value.
I have tried changing the values of the radio buttons to a variety of different values, but to no avail.
What value should I pass to RadioButtonFor to get this to work?
Ideally this editor template takes in nullable float and still works.
Duration.cshtml
#model float
<h3>Model Value: #Model</h3>
#Html.RadioButtonFor(model => model, 0.25F, new { id = "btnQuarterDay" }) #(.25F)
#Html.RadioButtonFor(model => model, 0.5F, new { id = "btnHalfDay" }) #(.5F)
#Html.RadioButtonFor(model => model, 0.75F, new { id = "btnThreeQuarterDay" }) #(.75F)
#Html.RadioButtonFor(model => model, 1.0F, new { id = "btnOneDay" }) #(1.0F)
Test.cs
public class Test
{
[UIHint("Duration")]
[Display(Name = "Days")]
public float Duration { get; set; }
}
HomeController
public class HomeController : Controller
{
public ActionResult Index(float? duration = null)
{
var model = new Test
{
Duration = duration.GetValueOrDefault(1F)
};
return View(model);
}
[HttpPost]
public ActionResult Index(Test model)
{
ViewBag.Success = true;
ViewBag.ValueSelected = model.Duration;
return View(model);
}
}
Index.cshtml
#model RadioButtonForTest.Models.Test
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<div class="row">
<div class="col-md-4">
#Html.EditorFor(model => model.Duration)
#Html.ValidationMessageFor(model => model.Duration)
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
if (ViewBag.Success ?? false)
{
<span>Value Selected:</span> #ViewBag.ValueSelected
}
}
UPDATE: Plot Thickener
I wired up the Index action to take in duration, so that I can pass it via the query string. If a value is not passed via the query string. It will select the radio button below:
#Html.RadioButton("", Model, Model.Equals(1.0F), new { id = "radbtnOneDay4" })
If I navigate to the query string /Home/Index?duration=.5
NOTHING is selected, but when debugging Duration.cshtml Model.Equals(.50F) reports TRUE. So I would expect this radio button to be selected:
#Html.RadioButton("", Model, Model.Equals(.50F), new { id = "radbtnHalfDay4" })
Is this not crazy? Why is it not checking this radio button??? Is this a bug? Is there a custom model binders I could add to handle floats?
UPDATE 2
The query string parameter duration matches the model name and the query string is overriding the model value.
When I changed the parameter to be dur it worked fine. Using the following URL it would use the value from the ViewModel.
/Home/Index?dur=.5
I know there is a solid reason behind this...but this has been exasperating.
The RadioButtonFor helper does not work in templates (edit: ... in cases like yours when using it to bind to simple member values as model => model expression will become an empty name). You need to change your template code to
#Html.RadioButton("", 0.25F, Model == 0.25F, new { id = "btnQuarterDay" }) #(.25F)
#Html.RadioButton("", 0.5F, Model == 0.5F, new { id = "btnHalfDay" }) #(.5F)
#Html.RadioButton("", 0.75F, Model == 0.75F, new { id = "btnThreeQuarterDay" }) #(.75F)
#Html.RadioButton("", 1.0F, Model == 1.0F, new { id = "btnOneDay" }) #(1.0F)
Edit#2: another alternative would be to use a more complex model:
public class DurationContainer {
public float Duration { get; set; }
}
public class Test2 {
[UIHint("Duration2")]
public DurationContainer Container { get; set; }
}
Index.cshtml:
#Html.EditorFor(model => model.Container)
And then as Duration2.cshtml template:
#Html.RadioButtonFor(model => model.Duration, 0.25F, new { id = "btnQuarterDay" }) #(.25F)
#Html.RadioButtonFor(model => model.Duration, 0.5F, new { id = "btnHalfDay" }) #(.5F)
#Html.RadioButtonFor(model => model.Duration, 0.75F, new { id = "btnThreeQuarterDay" }) #(.75F)
#Html.RadioButtonFor(model => model.Duration, 1.0F, new { id = "btnOneDay" }) #(1.0F)
Your editor template is not working because the first argument of is supposed to be a member expression to models property and not a model itself so model => model is what's wrong. You can easily fix it by using Html.RadioButton instead of `Html.RadioButtonFor. Notice that instead of specifying a property name we simply passing an empty string. The reason for that is that EditorTemplates generate are generating correct property names by appending prefixes form parrent model. So your template should look like that:
#model float
<h3>Model Value: #Model</h3>
#Html.RadioButton("", 0.25F, new { id = "btnQuarterDay" }) #(.25F)
#Html.RadioButton("", 0.5F, new { id = "btnHalfDay" }) #(.5F)
#Html.RadioButton("", 0.75F, new { id = "btnThreeQuarterDay" }) #(.75F)
#Html.RadioButton("", 1.0F, new { id = "btnOneDay" }) #(1.0F)

MVC 4 Bind multiple model asp razor

I develop an application who manages formations of employees, I use MVC4 Asp.net with Razor.
In my model I have tow class (who are table in my database) formation and formateur (trainers).
In my application i can create a “formation” and I want to add a list of “formative”(trainers) but I don’t know what I must do.
I think the best solution it’s a list of checkbox, I succeeded to display my list of checkbox with a foreach but I have no idea how I get the result of selected checkbox to pass into my controller.
I saw many tutorials where use “CheckBoxList” and I tried to use too, but I use a ViewBag to populate it and they don't explain how to use it with a viewbag.
Now I test a Dual listBox with tow buttons (Add and Remove) but this doesn't work.
So, somebody can help me to find, and explain how I must do, the good or the best solution ?
I'm sorry for my english, I'm a french girl.
One of my solutions look like this :
My controller :
public ActionResult Create()
{
ViewBag.formateurListe = (from unFormateur in db.salarie
where unFormateur.sFormateur == true
select unFormateur).AsEnumerable()
.Select(m => new SelectListItem
{
Text = m.sNom.ToString() + " " + m.sPrenom.ToString(),
Value = m.sId.ToString()
}).ToList();
return View();
}
[HttpPost]
public ActionResult Create(formation formation, IEnumerable<SelectList> formateurList)
{
if (ModelState.IsValid)
{
db.formation.Add(formation);
foreach (var unSal in formateurList)
{
formateur f = new formateur();
f.ftIdFormation = formation.fId;
f.ftIdSalarie = (int)unSal.SelectedValue;
db.formateur.Add(f);
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(formation);
}
In my view :
#model MvcAppGestionRH.Models.formation
#using (Html.BeginForm("Create", "Formation", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
#Html.Label("Libelle")
#Html.EditorFor(model => model.fLibelle)
#Html.ValidationMessageFor(model => model.fLibelle)
<label id="fFormateur">Formateur</label>
#Html.ListBox("formateurListe", ViewData["formateurListe"] as SelectListItem[], new {Multiple = "multiple"})
<input type="button" value="+" name="add" />
<select name="select" size="7" >
</select>
<input type="submit" value="Créer" />
}
With a script :
$(function () {
$("#Add").click(function () {
$("select").add($('fFormateurListe').selected);
});
});
Checkboxes can be tricky the first time - I googled that a long time, too.
My solution is a view model which looks like this:
It is intended for questions, where the crator can speciy items via checkboxes (e.g. a questions might have the answer "GOOD" and "BAD".
public class QuestionModel
{
public int QuestionID { get; set; }
public string QuestionText { get; set; }
/// <summary>
/// Gets or sets the selected items. Purely a helper List to display check boxes for the user
/// </summary>
/// <value>
/// The selected items.
/// </value>
[Display(Name = "Items", ResourceType = typeof(Domain.Resources.Question))]
public IEnumerable<SelectListItem> SelectedItems { get; set; }
/// <summary>
/// Gets or sets the selected ids. Populated by the user, when he checks / unchecks items. Later translated into QuestionItems
/// </summary>
/// <value>
/// The selected ids.
/// </value>
public int[] SelectedIds { get; set; }
}
This is populated like this in the QuestionController:
private async Task GetSelectedItems(QuestionModel sm, Item selectedItems)
{
var alreadySelected = new List<Scale>();
if (selectedScale != null)
{
alreadySelected.Add(selectedScale);
}
var itemList = (await this.uoW.ItemRepository.Get()).OrderBy(i => i.Name);
sm.SelectedItems = itemList.Select(x => new SelectListItem
{
Value = x.ScaleID.ToString(),
Text = x.NameOfScale.GetText(),
Selected = (from a in alreadySelected where a.ItemID == x.ItemID select x).Any()
});
}
What does this do? It gets a list of all avialable items in the database and populates the model with it. Furthermore, you can pass in a list of items, which are already selected - so you can edit an existing question and siplay all already checked Items.
And n the view I have used a DropDownList:
<div class="form-group">
#Html.LabelFor(model => model.SelectedItems, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.DropDownListFor(x => x.SelectedIds, Model.SelectedItems, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.SelectedItems, "", new { #class = "text-danger" })
</div>
</div>
</div>
If you want checkboxes, that looks like this(different controller, so dont be confused)
for (int i = 0; i < Model.SelectedItems.Count(); i++)
{
var currentElem = Model.SelectedItems[i];
//if this item is selected by the user, e.g. because he is editing the item, the item will be pre-selected
var selected = currentElem.Selected ? "checked=\"selected\"" : string.Empty;
// column for the questions. expected layout: list of all questions
<div class="col-md-6">
<div class="checkbox" id="SelectedIds">
<label>
<input type="checkbox" value="#currentElem.Value" #selected name="SelectedIds">
#Html.Encode(currentElem.Text)
</label>
</div>
</div>
}
and finally the create() method itself:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "QuestionText,SelectedItems, SelectedIds")] QuestionModel question)
{
if (ModelState.IsValid)
{
// I need only one Item, but if you want ore more change this line
if (question.SelectedIds.Count() == 1)
{
// better use Automapper here, this is unnecessary work
var newQuestion = new Question { QuestionText = question.QuestionText};
var ItemID = question.SelectedIds.First();
newQuestion.QuestionScale = await this.uoW.ItemRepository.GetRaw().Where(i => i.ItemID == ItemD).FirstAsync();
this.uoW.QuestionRepository.Insert(newQuestion);
await this.uoW.Save();
return this.RedirectToAction("Index");
}
else
{
this.logger.Warn("User {0} tried to insert more than one Itemin question {1}", User.Identity.Name, question.QuestionID);
ModelState.AddModelError(string.Empty, xyz.Areas.QuestionManagement.Resources.QuestionRes.ErrorTooManyScales);
}
}
else
{
// the SelectedItems are empty in the model - so if you have to redisplay it, repopulate it.
await this.GetSelectedItems(question, null);
}
return this.View(question);
}
Have you tried using a viewmodel to pass your two model in the view?
For example :
ViewModel
public class CreateFormationViewModel
{
public Formation formation{ get; set; }
public List<Formative> trainers {get;set;}
}
and then use this viewmodel in your view
An easy way to use this view model :
In your controller
public ActionResult CreateFormation()
{
//Get your data (formation and trainer)
CreateFormationViewModel createFormationVM = new CreateFormationViewModel();
createFormationVM.formation = YourFormationModel;
createFormationVM.trainers = YourtrainersModelasList;
//bind data to the view
return View(createFormationVM);
}
And in your View, you have :
#model [yournamespace].CreateFormationViewModel

mvc dropdown not showing selected index

I have the following on my controller:
string preferredLanguage = "fr-ca";
ViewData["Languages"] = new SelectList(languages, "Code", "Name", preferredLanguage);
On the view:
#Html.DropDownList("Languages", (SelectList)ViewData["Languages"], new { id = "Languages" });
My problem here is my dropdown is not setting the selected index of dropdown to the preferred language which is supposed to be French.
Note:
The values inside the languages:
1) Name = "English"
Code = "en-us"
2) Name = "French"
Code = "fr-ca"
And the dropdown shows two languages, English and French. English is set as selected index but what I want is French.
The reason I show the languages this way because this object are being retrieved from the database my a method and not by hardcoded. Thanks in advance!
I'd recommend using strongly-typed helpers bound to a model; something along these lines:
Model:
public class LanguageFormModel
{
public string SelectedLanguage { get; set; }
public SelectList Languages { get; set; }
}
Action:
[HttpGet]
public ActionResult YourActionName()
{
// replace this with however you're getting your language variable
var languages = new CollectionOfSomeSort();
var model = new LanguageFormModel()
{
SelectedLanguage = "fr-ca",
Languages = new SelectList(languages, "Code", "Name", "fr-ca")
};
return View(model);
}
View:
#model Your.Fully.Qualified.Namespace.LanguageFormModel
#Html.LabelFor(m => m.SelectedLanguage)
#Html.DropDownListFor(m => m.SelectedLanguage, Model.Languages, "Select one...")
I'm personally not a huge fan of using ViewData for anything other than simple messages, and even then I use TempData, since I'm mostly just showing confirmations/alerts.
This is working fine for me.
Dictionary<string, string> languages = new Dictionary<string, string>() { { "en-us", "English" }, { "fr-ca", "French" } };
ViewData["Languages"] = new SelectList(languages, "key", "value", "fr-ca");
IN VIEW
#Html.DropDownList("Language", ViewData["Languages"] as SelectList, new { id = "Languages" })
this is ok:
#Html.DropDownList("languages")

mvc 4 drop down default value selected

I want to select the default value in drop down list where policyId = 7 but it didn't select that value, what i am doing wrong?
Controller:
var pm = new ManagerClass();
IEnumerable<myClass> po = pm.GetDataFromDb();
IEnumerable<SelectListItem> Policies = new SelectList(po, "PolicyID", "PolicyName", new { PolicyID = 7 });
ViewBag.Policies = Policies;
View:
#Html.DropDownListFor(m => m.PolicyID, ViewBag.Policies as IEnumerable<SelectListItem>, new { #class = "dropdown-field"})
It's because it's not actually selecting the value in the SelectList.
First, to make it nicer, put the items in your view model to prevent the cast (this is better practice too):
public class MyModel
{
public int PolicyID { get; set; }
public List<SelectListItem> Policies { get; set; }
//rest of your model
}
Then populate it:
var model = new MyModel();
model.Policies = po
.Select(p => new SelectListItem
{
Text = p.PolicyName,
Value = p.PolicyID.ToString(),
Selected = p.PolicyID == currentPolicyId //change that to whatever current is
})
.ToList();
Then in your view, do:
#Html.DropDownListFor(m => m.PolicyID, Model.Policies, new { #class = "dropdown-field"})
Just set the PolicyID property on your view model to the value you want to be preselected:
var pm = new ManagerClass();
var po = pm.GetDataFromDb();
ViewBag.Policies = new SelectList(po, "PolicyID", "PolicyName");
viewModel.PolicyID = 7;
return View(viewModel);
Since your DropDownList is bound to the PolicyID property (m => m.PolicyID), then its value will be used when deciding which element to be preselected.
In case that you have a static menu:
1- create the following class:
public static class StaticMenus
{
public static List<string> GetGridRowsCount()
{
List<string> result = new List<string>();
result.Add("3");
result.Add("5");
result.Add("10");
result.Add("20");
result.Add("25");
result.Add("50");
result.Add("100");
return result;
}
}
2- add the following code to your controller :
ViewData["CountryList"] = new SelectList(StaticMenus.GetGridRowsCount(),"10");
3- add the following code to your view:
#Html.DropDownList("MainGridRowsCount", ViewData["RowsCountList"] as SelectList)

Categories