Html.DropDownList populating - asp.net-mvc

I have a drop down in my MVC project.
#Html.DropDownList("Chart Type", new List<SelectListItem>
{
new SelectListItem{ Text="Horizontal", Value = "Horizontal" },
new SelectListItem{ Text="Vertical", Value = "Vertical" },
new SelectListItem{ Text="Pie", Value = "Pie" }
},
new { #class = "chzn-select", #multiple ="true", #style="width:350px;"} )
This puts hard coded values in the list.
If I want to get the values from a database, what is the best approach?
Can I have the Html.DropDownList reference a sql query or SP for populating the list?

Create a view model with (at least) two properties:
public class ViewModel()
{
public List<SelectListItem> Items { get; set; }
public string SelectedItem { get; set; }
}
In your controller, make the call to your data source and populate the Items property of the view model and pass it to the view.
public ActionResult Index()
{
var viewModel = new ViewModel();
viewModel.Items = database.GetChartTypes();//or however you're accessing your data
return View(viewModel);
}
Then strongly type your view and use the DropDownListFor helper
#model MyProject.ViewModel
...
#Html.DropDownListFor(m => m.SelectedItem,
Items,
"--Select a Chart Type--",
new { #class = "chzn-select",
#multiple ="true",
#style="width:350px;"
});

You do not want the UI making calls to your data layer.
What you would want is the controller either calling a "service" that then calls the repository, or the controller calling the repository to get the list.
Once it has the list, it will pass that to the view using a ViewModel or the ViewBag.

Related

Formatting a Drop Down List in ASP.NET MVC

I'm building an app with ASP.NET MVC 4. I'm binding my model to a view. In my view, I need a drop down list. That drop down list needs to show quarters. The quarters should be displayed as "Q1", "Q2", "Q3", and "Q4". My model, only has quarter numbers. They are defined like this:
public List<short> Quarters = new List<short>() { get; set; }
public short? SelectedQuarter = null;
public void Initialize() {
Quarters.Add(1);
Quarters.Add(2);
Quarters.Add(3);
Quarters.Add(4);
}
Somehow, I need to prepend "Q" to each value. However, I'm not sure how to do this in ASP.NET MVC. How does someone do this?
Thanks!
Create a SelectList to be used by DropdownListFor() so that you bind the selected option to property SelectedQuarter, but display the 'friendly' name.
View model
public class MyViewModel
{
[Display(Name = "Quarter")]
[Required]
public short? SelectedQuarter { get; set; } // must be a property, not a field!
IEnumerable<SelectListItem> QuarterList { get; set; }
}
Controller
public ActionResult Edit()
{
MyViewModel model = new MyViewModel();
ConfigureViewModel(model);
return View(model);
}
public ActionResult Edit(MyViewModel model)
{
if(!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
// model.SelectedQuarter contains the selected value
}
private void ConfigureViewModel(model)
{
model.SelectedQuarter = new List<SelectListItem>()
{
new SelectListItem() { Value = "1", Text = "Q1" },
new SelectListItem() { Value = "2", Text = "Q2" },
new SelectListItem() { Value = "3", Text = "Q3" },
new SelectListItem() { Value = "4", Text = "Q4" },
}
}
View
#model MyViewModel
#using(Html.BeginForm())
{
#Html.LabelFor(m => m.SelectedQuarter)
#Html.DropDownListFor(m => m.SelectedQuarter, Model.QuarterList, "-Please select-")
#Html.ValidationMessageFor(m => m.SelectedQuarter)
<input type="submit" />
}
Assuming you have this property:
public List<short> Quarters { get; set; }
Then in your view or any other consuming code you can generate a list of strings with something like:
model.Quarters.Select(q => "Q" + q)
or:
model.Quarters.Select(q => string.Format("Q{0}", q))
However, semantically it really feels like this belongs on a view model and not in consuming code. Ideally the view should only ever need to bind directly to properties on the view model, not transform those properties. Something like this:
public IEnumerable<string> QuartersDisplay
{
get { return Quarters.Select(q => string.Format("Q{0}", q)); }
}
Then consuming code can just bind to that property:
model.QuartersDisplay
(If the model is a domain model then I'd recommend introducing a view model between the domain and the view, since this wouldn't belong on a domain model.)
Thinking about this a little more... Do you want one property with both the displays and the backing values for the drop down list? That would likely be a IDictionary<short, string>, I imagine? Something like this:
public IDictionary<short, string> QuartersOptions
{
get { return Quarters.ToDictionary(q => q, q => string.Format("Q{0}", q)); }
}
In which case you'd bind to that property:
model.QuartersOptions
Keep in mind that a drop down list often binds to two things. The property which holds the list of possible values (which is what we've built here) and the property which holds the selected value (which remains your SelectedQuarter property).

MVC 5 DropDownListFor Database Linq;

Can anyone please tell me how to write Controller for C# (public ActionResult DropList()) for Drop Down List generate Linq I want convert this SELECT DISTINCT CouName FROM Locations; to Linq for my drop down list dynamically generate.
Chtml page how do I write in #Html.DropDownListFor("")
Models.Location
This code will generate a select list from an IQueryable GetAll() method, or you could use it on your entity directly using from c in _context.Set<Location>()
public SelectList GetAsSelectList()
{
var locs = from c in GetAll()
select new
{
Id = c.Id,
Name = c.Name
};
return new SelectList(locs, "Id", "Name");
}
Where Id is the Value field and Name is the Text field of the selectlist options.
This would be assigned to a model property:
var model = new MyModel
{
LocationList = GetAsSelectList();
}
You would pass the model to your View, and use DropDownListFor:
#Html.DropDownListFor(x => x.MyModel.Location, Model.LocationList)
Your model would also have a Location property which you would set to display a default value if you wanted to do that.
Assuming you model is named MyModel
Controller
public ActionResult Edit()
{
var couriers = // get your couriers from the database using your query
// Is better to assign this to a property in your view model, but ViewBag will do for now
ViewBag.CourierList = new SelectList(couriers);
var model = new YourModel();
}
View
#model YourModel
#using(Html.BeginForm())
{
#Html.DropDownListFor(m => m.CouriersName, (SelectList)ViewBag.CourierList)
}
As far as i have understood, you can do something like this:
public ActionResult DropList()
{
List<SelectListItem> objResult = new List<SelectListItem>();
var result = dbContext.Locations.Select(x=>x.CouName).Distinct().ToList();
foreach(var item in result)
{
SelectListItem temp = new SelectListItem();
temp.Text = item;
temp.Value = item;
objResult.Add(temp);
}
ViewBag.DropdownResult = objResult;
return View();
}
Dropdown in view:
#Html.DropDownListFor(m=>m.ModelLocations, ViewBag.DropdownResult as List<SelectListItem>)
Please modify the code as per your need.
using System.Web.Mvc;
...
public static List<SelectListItem> GetItemsForDisplay(string listName)
{
//your data access function should return a list of objects
return DAL.Table.SelectByName(listName)
.Select(x=> new SelectListItem{Text=x.DisplayName, Value=x.ID})
.ToList<SelectListItem>();
}

Dropdownlist client side required validation (without model)

View:
#Html.DropDownList("CategoryItems", null, new { #class = "ddlcs" })
#Html.ValidationMessage("CategoryItems")
Controller:
var cat = from s in db.CategoryDbSet
where s.IsActive == true
orderby s.CatName
select new { s.CatID, s.CatName };
var catListItems = cat.ToList()
.Select(c => new SelectListItem
{
Text = c.CatName,
Value = c.CatID.ToString()
})
.ToList();
catListItems.Insert(0, new SelectListItem
{
Text = "[--Select the category--]",
Value = ""
});
ViewBag.CategoryItems = catListItems;
I wish to enforce the required validation on the dropdown when someone selects the "Select the category" option during the save action. I am new to MVC framework and i am not sure where am i making the mistake ? This dropdown is not tied up with the Model.
Please suggest the soln.
This dropdown is not tied up with the Model.
That's the mistake. Validation in ASP.NET MVC works by decorating your view model properties with the respective attributes. For example if you want to make this dropdown required, you would decorate the corresponding property on your view model with the [Required] attribute.
So add the necessary properties to your existing view model:
public class MyViewModel
{
[Required]
public int? SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
... some other properties that your view might need
}
and then in your controller action populate this view model:
var model = new MyViewModel();
model.Categories = cat
.ToList()
.Select(c => new SelectListItem
{
Text = c.CatName,
Value = c.CatID.ToString()
}).ToList();
return View(model);
and in your view use the strongly typed versions of the helpers:
#Html.DropDownListFor(
x => x.SelectedCategoryId,
Model.Categories,
"[--Select the category--]",
new { #class = "ddlcs" }
)
#Html.ValidationMessageFor(x => x.SelectedCategoryId)
If you want only client side validation, you may do this:
$('form').validate({
rules:{
CategoryItems: 'required'
}
});
Working demo.
But I wouldn't suggest doing so as the client side validation is for better user experience and can be easily bypassed. The correct way to do this is described in Darin's answer, using dataannotations and view models.

How do I add a Custom Query for a drop down and retain the View Model Pattern?

I've read many articles which they state that querying should not be placed in the Controller, but I can't seem to see where else I would place it.
My Current Code:
public class AddUserViewModel
{
public UserRoleType UserRoleType { get; set; }
public IEnumerable<SelectListItem> UserRoleTypes { get; set; }
}
public ActionResult AddUser()
{
AddUserViewModel model = new AddUserViewModel()
{
UserRoleTypes = db.UserRoleTypes.Select(userRoleType => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)userRoleType.UserRoleTypeID).Trim(),
Text = userRoleType.UserRoleTypeName
})
};
return View(model);
}
The View:
<li>#Html.Label("User Role")#Html.DropDownListFor(x => Model.UserRoleType.UserRoleTypeID, Model.UserRoleTypes)</li>
How do I retain the View Model and Query and exclude the User Type that should not show up?
I think that you are doing it just fine.
Any way... all you can do to remove the querying logic from controller is having a ServiceLayer where you do the query and return the result.
The MVC pattern here is used correctly... what your are lacking is the other 2 layers (BusinessLayer and DataAccessLayer)... since ASP.NET MVC is the UI Layer.
UPDATE, due to comment:
Using var userroletypes = db.UserRoleTypes.Where(u=> u.UserRoleType != 1);
is OK, it will return a list of UserRoleType that satisfy the query.
Then, just create a new SelectList object using the userroletypes collection... and asign it to the corresponding viewmodel property. Then pass that ViewModel to the View.
BTW, I never used the db.XXXX.Select() method before, not really sure what it does... I always use Where clause.
SECOND UPDATE:
A DropDownList is loaded from a SelectList that is a collection of SelectItems.
So you need to convert the collection resulting of your query to a SelectList object.
var userroletypes = new SelectList(db.UserRoleTypes.Where(u=> u.UserRoleType != 1), "idRoleType", "Name");
then you create your ViewModel
var addUserVM = new AddUserViewModel();
addUserVM.UserRoleTypes = userroletypes;
and pass addUserVM to your view:
return View(addUserVM );
Note: I'm assuming your ViewModel has a property of type SelectList... but yours is public IEnumerable<SelectListItem> UserRoleTypes { get; set; } so you could change it or adapt my answer.
I don't see anything wrong with your code other than this db instance that I suppose is some concrete EF context that you have hardcoded in the controller making it impossible to unit test in isolation. Your controller action does exactly what a common GET controller action does:
query the DAL to fetch a domain model
map the domain model to a view model
pass the view model to the view
A further improvement would be to get rid of the UserRoleType domain model type from your view model making it a real view model:
public class AddUserViewModel
{
[DisplayName("User Role")]
public string UserRoleTypeId { get; set; }
public IEnumerable<SelectListItem> UserRoleTypes { get; set; }
}
and then:
public ActionResult AddUser()
{
var model = new AddUserViewModel()
{
UserRoleTypes = db.UserRoleTypes.Select(userRoleType => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)userRoleType.UserRoleTypeID).Trim(),
Text = userRoleType.UserRoleTypeName
})
};
return View(model);
}
and in the view:
#model AddUserViewModel
<li>
#Html.LabelFor(x => x.UserRoleTypeId)
#Html.DropDownListFor(x => x.UserRoleTypeId, Model.UserRoleTypes)
</li>

MVC SelectList not working

List<SelectListItem> items = new List<SelectListItem>();
if (a)
{
SelectListItem deliveryItem = new SelectListItem()
{
Selected = a.selected,
Text = "Delivery",
Value = "1"
};
items.Add(deliveryItem);
}
if (b)
{
SelectListItem pickupItem = new SelectListItem()
{
Selected = b.selected,
Text = "Pickup",
Value = "2"
};
items.Add(pickupItem);
}
SelectList selectList = new SelectList(items);
ViewData["OrderTypeList"] = selectList;
Then using it with
Html.DropDownList("OrderTypeList")
Renders
<select id="OrderTypeList" name="OrderTypeList"><option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
</select>
Why it is not rendering options properly?
The constructor method you're calling when you do:
SelectList selectList = new SelectList(items);
Creates a set of SelectListItems that themselves point to SelectListItems (hence the weird option since it just calls ToString on the object). Instead set your list to the ViewData key directly
ViewData["OrderTypeList"] = items;
You could have also simply changed the one line from:
SelectList selectList = new SelectList(items);
to
SelectList selectList = new SelectList(items, "Text", "Value");
This will instruct MVC which properties to use as the Text and Value in your option tags.
Or you could create a class that will hold the select list and then return the class as the views model. I think that's a much more elegant way of doing it rather than ViewData.
public class MyFormViewModel
{
public SelectList Friends { get; set; }
}
Then in your ActionResult
MyFormViewModel fvm = new MyFormViewModel();
fvm.Friends = new SelectList(myList, "UserName", "NickName");
Then in your view
<%= Html.DropDownList("ToUserName", Model.Friends, new { #class = "field" })%>
If you look at the Intellisense for the SelectList constructor overloads, the code SelectList(items) should work, but doesn't. The fact that it simply does a ToString() on items is, as far as I can tell, a bug that Microsoft should fix. The answers are all nice workarounds. BTW, if you use the method supplying "Text" and "Value", the correct answer should be
SelectList selectList = new SelectList(items, "Value", "Text")
not
SelectList selectList = new SelectList(items, "Text", "Value")
At least, that agrees with my experimentation in MVC 3.
I think you should try rendering with
Html.DropDownList("OrderTypeList", ViewData["OrderTypeList"])

Resources