Unable to populate dropdonwlist with pre-selected value.Populating with pre-selected value works with viewbag method.However when i am trying the same with a Model based method i find no luck.
public ActionResult Edit(int?id)
{
Job_ClientVM Vm = new Job_ClientVM();
Vm.Job_Info = Get_jobdetails(id);
//4 is desired pre-selected ID value
Vm.Recruiters = new SelectList(db.Recruiter_Info.ToList(), "Id",
"Recruiter_Name",4);
}
Here is my View
#Html.DropDownListFor(Model => Model.SelectedRecruiterID, Model.Recruiters, "Assign Recruiter", new { #class = "form-control" })
You need to set the value of SelectedRecruiterID in the GET method before you pass the model to the view.
public ActionResult Edit(int?id)
{
Job_ClientVM Vm = new Job_ClientVM();
Vm.Job_Info = Get_jobdetails(id);
Vm.Recruiters = new SelectList(db.Recruiter_Info.ToList(), "Id", "Recruiter_Name");
// Set the value of SelectedRecruiterID
Vm.SelectedRecruiterID = 4;
// Pass the model to the view
return View(Vm);
}
Note that setting the Selected property (the 4th parameter) in the SelectList constructor is pointless - its ignored when binding to a model property (internally the method builds a new IEnumerable<SelectListItem> and sets the Selected property based on the value of the property.
Related
I have a requirement where when a user clicks on image a list should be shown with checkboxes and all the categories that is present in DB and user should be able to select the checkboxes. How can this be achieved using asp:repeater control? the caegory is a enum type and can have n number of values. In repeater i have added a checkbox and a label; the label should display the category text.
To start with, you should add the [Description] attribute to each value in your Enum. This allows you to set proper descriptive text for each value. This attribute is in System.ComponentModel, here's an example: -
public enum CalendarShowAsEnum
{
[Description("None")]
None = 10,
[Description("Busy")]
Busy = 20,
[Description("Out Of Office")]
OutOfOffice = 30,
[Description("On Holiday")]
OnHoliday = 40
}
You then need 2 functions: -
One function that takes an Enum type and a ListBox/DropDown as parameters, and adds an entry for each Enum into the list
A helper function that converts the enum into the descriptive title you gave them (example above)
The List function might look as follows (all this is taken from a project I worked on): -
public static void BindNamedEnumList(ListControl list,
Type enumerationType)
{
list.Items.Clear();
Array array = Enum.GetValues(enumerationType);
ListItem item;
string name;
var enumerator = array.GetEnumerator();
if (enumerator != null)
{
while (enumerator.MoveNext())
{
Enum value = enumerator.Current as Enum;
name = EnumHelper.GetEnumName(value);
item = new ListItem(name);
item.Value = Convert.ToInt32(value).ToString();
list.Items.Add(item);
}
}
}
This function takes a Type and a ListControl (which ListBox and DropDownList both inherit from). The Type is the .GetType() of the enum you want to add to the list. Note that it doesn't select any values and that it does depend on each enum value having a defined integer value. The latter part will help you with selecting individual items.
Note the loop calls EnumHelper.GetEnumName(value) - this is the helper function that uses the Description attribute I mentioned at the start. This function looks like: -
public static string GetEnumName(object value)
{
string retVal = string.Empty;
try
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
retVal = ((attributes.Length != 0) ? attributes[0].Description : value.ToString());
}
catch (System.NullReferenceException)
{
}
finally
{
if (string.IsNullOrEmpty(retVal))
{
retVal = "Unknown";
}
}
return retVal;
}
It uses reflection, so you'll need to add an Imports for System.Reflection
To use the list function to bind a set of Enum values to the list, simply call
{HelperClass}.BindNamedEnumList(myListBox, typeof({MyEnumType})
I have a selection of names, drawn from my database, to which I prepend the option "None" in my Controller:
var rtrnStaff = (from st in db.PrmTbl_Staffs
join sal in db.PrmTbl_Salutations on st.SalutationID equals sal.ID
where st.Active == true
select new { st.ID, Name = sal.Desc + ". " + st.Name });
List<SelectListItem> staff = new SelectList(rtrnStaff, "ID", "Name").ToList();
staff.Insert(0, (new SelectListItem { Text = "None", Value = "0" }));
ViewData["Staff"] = staff;
I then present this list as a dropdown multiple times in my View, where each time I feed it a variable containing the ID of the desired default option:
#Html.DropDownList(thisSelectID, (IEnumerable<SelectListItem>)ViewData["Staff"], thisStaffID)
Using breakpoints, I can see that these variables are being filled correctly (eg. "3", "2", etc.), but in every case the option shown is the first one: "None". Where is my error?
When you use DropDownList you don't have any way to set the selected value but in the list itself. None of the overloads allows to do it.
So, if you only have one list, it's unavoidable to have all the controls with the same selected item.
Most times it's much better, and make the code much more clear to use a view model class for your view, and use DropDownListFor.
When you use DropDowListFor you set the default property value in the property of the view model, and you don't have to do anything special to set the selected value.
I.e. create a class like this:
public class MyViewModel
{
public List<SelectListItem> Staff { get; set; }
public int FirstId { get; set; }
public int SecondId { get; set; }
}
Then, in your view,
#model MyViewModel
...
#Html.DropDownListFor(m => m.FirstId, Model.Staff);
#Html.DropDownListFor(m => m.SecondId, Model.Staff);
Create an instance of MyViewModel, intialize the list and the Ids, and pass it to the View
MyViewModel model = new MyViewModel
{
// Initialize here
};
...
return View("ViewName", model);
There are additional advantages: you can use the same view model class as the parameter for the POST action method, and the properties are automatically bound to the corresponding properties, you have Intellisense and a typed view is safer to implement.
I got the following Model:
public class ViewBloqueioNotaFiscal
{
public ViewComboStatus ComboStatus = new ViewComboStatus();
public class ViewComboStatus
{
public int? IdStatusSelecionado { get; set; }
public IEnumerable<SelectListItem> ComboStatus { get; set; }
}
}
The following controller method:
public ViewBloqueioNotaFiscal.ViewComboStatus geraComboStatus(int? statusSelecionado)
{
ViewBloqueioNotaFiscal.ViewComboStatus combo = new ViewBloqueioNotaFiscal.ViewComboStatus
{
IdStatusSelecionado = statusSelecionado,
ComboStatus = new[]{
new SelectListItem { Value = 1, Text = "Op1"},
new SelectListItem { Value = 2, Text = "Op2"}
}
};
return combo;
}
And my aspx is like:
<%: Html.DropDownListFor(x => x.ComboStatus.IdStatusSelecionado, Model.ComboStatus.ComboStatus) %>
Its getting perfectly displayed for selection but when I submit my form, my post method from controller gets the model perfectly with the values except for this combo that Im recieving null value into the model. As its the first one that I try, I think that something is wrong.
Could you guys check that for me? If you have any better solution for this I d like to know too.
thanks for the help !
You are not binding to the correct property of your view model. You are binding to some complex object (ComboStatus) which doesn't make sense.
You should bind the drop down list to the IdStatusSelecionado property:
<%: Html.DropDownListFor(
x => x.ComboStatus.IdStatusSelecionado,
Model.ComboStatus.ComboStatus
) %>
A strongly typed DropDownListFor helper requires at least 2 things on your view model:
A scalar property (int, decimal, string, ...) which will be used to bind to
A collection of value/text pairs.
If the collection of value/text pairs contains an item whose value is equal to the scalar property you used as first argument, this item will be preselected. For example if you wanted to preselect the second item in your example you would set IdStatusSelecionado=2 on your view model.
Side note: Model.ComboStatus.ComboStatus looks terrible. Please rename.
I am trying to pass a variable from a method in my Controller to a method in a Model. Since the method in the Model takes one argument (which was designed earlier), I cannot pass my variable as an argument to the method in the Model. And also, the method in this Model is called by other controllers too, so if I change the argument, I have to change all the controllers too, which would be a tedious task.
What I have been trying so far is- I created one MyVariableClass and declared a property. Then I instantiated that class and set the property string to the variable that I wanted to pass. Now, in my Model's method, I instantiated the same MyVariableClass again, but when I did that, the value of the variable was set to null. The code I have right now is -
public ActionResult ItemInformation( string id)
{
//Pass a string to MyVariable
MyVariableVClass params = new MyVariableClass();
params.myVariable = "abc";
//This is what My Model is taking as an argument(id), and I don't want to
//pass mYvariable along with that argument because it will break other controllers
// too which calls this method
var itemInformation = _repository.GetItemInformation(id);
return View(itemInformation);
}
and MyVariableClass
public class MyVariableClass
{
public string myVariable { get; set; }
}
and the method in My Model
public IList<Items> GetItemInformation(string itemId)
{
MyVariableClass webType = new MyVariableClass();
var _params = webType.myVariable;
//Check this variable and perform database query
if (_params =="this")
{
var query = myFirstQuery;
}
else
{
var query = mySecondQuery;
}
//return ....
}
Anybody has solution to this? Thanks in Advance!
Any reason why subclassing your model and overriding the GetItemInformation method wouldn't work? Or, even easier, why not just overload the GetItemInformation method with one that takes two strings? Your other controllers can still use the one that only takes a single string.
public IList<Items> GetItemInformation(string itemId, MyVariableClass webType)
{
var _params = webType.myVariable;
//Check this variable and perform database query
if (_params == "this")
{
var query = myFirstQuery;
}
else
{
var query = mySecondQuery;
}
//return ....
}
public IList<Items> GetItemInformation(string itemId)
{
MyVariableClass fauxType = new MyVariableClass();
fauxType.myVariable = "not this";
return GetItemInformation(itemId, fauxType);
}
Try using session variable.
In ASP.NET MVC, is it possible to fill the list of values of a Html.DropDownList from multiple data sources along with multiple manually entered values?
Basically, I envision it being formated like the below using something along the lines of OPTGROUP:
**Group 1**
Manual Item 1
Manual Item 2
**Group 2**
DS1 Item 1
DS1 Item 2
**Group 3**
DS2 Item 1
DS2 Item 2
I've thought about using a view on the DB and getting the data from that, however, I've not really the faintest how to lay it out like above using helpers and to pass the data to it from multiple sources.
Thanks for any help in advance.
As always start with a model (actually start with a unit test but no time for this here):
public class MyModel
{
public string SelectedItem { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
Then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var items1 = new[]
{
new { Value = "1", Text = "Manual Item 1" },
new { Value = "2", Text = "Manual Item 2" },
};
// TODO: Go fetch those from your repo1
var items2 = new[]
{
new { Value = "3", Text = "DS1 Item 1" },
new { Value = "4", Text = "DS1 Item 2" },
};
// TODO: Go fetch those from your repo2
var items3 = new[]
{
new { Value = "5", Text = "DS2 Item 1" },
new { Value = "6", Text = "DS2 Item 2" },
};
var items = items1.Concat(items2).Concat(items3);
var model = new MyModel
{
Items = new SelectList(items, "Value", "Text")
};
return View(model);
}
}
And finally a strongly typed view to the model:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyApp.Models.MyModel>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.DropDownListFor(x => x.SelectedItem, Model.Items) %>
</asp:Content>
You will probably define an intermediary type to avoid the anonymous types that I've used for brevity.
Remark: If your original question was about using an OPTGROUP then ignore my answer and make your intention clear so that you can get a more adapted answer.
It seems it would be easier for you to write your own helper. The basic syntax to do that is this:
// The class can be named anything, but must be static and accessible
public static class HtmlHelperExtensions
{
// The method name is what you want to call on Html,
// in this case Html.CoolSelectList(arguments...)
//
// The method has to be static, and the first argument should be of the type
// you're extending (in this case HtmlHelper, which is the type of the
// Html property on your view). The first argument must be prefixed with the
// "this" keyword, to indicate it's an extension method.
//
// All the following arguments will be arguments that you supply when calling
public static string CoolSelectList(this HtmlHelper helper,
IEnumerable<IEnumerable<CoolThingThatWeMakeAListOf>> groups)
{
// I chose an argument of type IEnumerable<IEnumerable<T>>, since that
// allows you to create each group of item on its own (i.e. get them from
// various data sources) and then add all of them to a list of groups
// that you supply as argument. It is then easy to keep track of which
// items belong to which groups, etc.
// Returned from the extension method is a string you have built, that
// constitutes the html you want to output on your view. I usually use
// the TagBuilder class to build the html.
return "this is what will be on the page";
}
}
Many solutions exist for you problem. One would be the one that Tomas described, another is a Controller Action that returns PartialView, which contains the code to render the input and option tags, another solution would be to have the Controller Action populate the ViewData with a SelectList or have the SelectList as a strong type for your View/ViewUserControl (Partial).