ASP.NET MVC dropdown-list from database - c#

Ok, so I'm new to this whole MVC-world, but it seems to be a pretty good way of getting things done and I'm trying to make it work here.
The problem is:
I can't get data from my table in my SQL-database to a simple drop-down form on my registration page.
I have just no idea where to put the stuff, where to code to open the table, select the ids, where to put the response.write and how do I send it to the view?
My Model is this:
public class users
{
public string name {get; set;}
public int user_id {get; set;}
}
My Controller is this:
[HttpGet]
public ActionResult ListUser()
{
return View();
}
And my View is this:
#model Community.Models.users
I have googled for 2 days now and watched several videos on youtube but of no use, I can't find it. Please, anyone with some knowledge here? And please point me to some good tutorials and/or forums where I can browse for more questions I might have
Still no luck on this project..
I'm creating a form and within that form, i want a db-loop (IEnumerable).. But the current model is not a IEnumerable. I'm pretty much stuck, watched a bunch of tutorials and they all just list ONE connection, what if I want two models?
Here is my Controller, I get that you must pass a list to the view, right?
public ActionResult Registration()
{
return View(db.users.ToList());
}
How do i get hold of that list in my view witout an IEnumerable model?
#neoistheone, your example didnt help me much, my DB opens like this:
private DataBaseContext db = new DataBaseContext();
and i don't know how, but it opens the connection.
I've tried for so many hours now, its just silly, haven't slept for soo long!
I'm used to programming ASP-Classic fyi, and this is my first serious try to upgrade my knowledge about programing an up-to-date language and OOP.

Add the SelectList to your model:
public SelectList DropDownList { get; set; }
build the class for that collection:
public class MyListTable
{
public string Key { get; set; }
public string Display { get; set; }
}
and then in your controller, load the data for the MyListTable class from the database:
var list = new List<MyListTable>();
using (SqlConnection c = new SqlConnection(cString))
using (SqlCommand cmd = new SqlCommand("SELECT KeyField, DisplayField FROM Table", c))
{
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
list.Add(new MyListTable
{
Key = rdr.GetString(0),
Display = rdr.GetString(1)
});
}
}
}
var model = new users();
model.DropDownList = new SelectList(list, "Key", "Display");
and then finally, you need to send your model to the view:
return View(model);
Now in the Razor you can display this:
#Html.DropDownListFor(m => Model.DropDownList);
You of course can name these things better names, but you get the idea.

There a great answers already but Here is another approach.
You will use user as a model, ListUserViewModel as view-model and UserController as the contoller. The work of view-model is to carry all info needed to be displayed on the page from the controller without adding unwanted properties into the model class. In your case list of users from database into the drop down list.
Model:
public class User //By the way use singular when naming a class
{
public string name {get; set;}
public int user_id {get; set;}
}
View-model
public class ListUserViewModel
{
public list<User> Users{get; set;}
}
Controller
public class UserController : Controller
{
private DataBaseContext db = new DataBaseContext();
[HttpGet]
public ActionResult ListUser()
{
var users = db.Users.ToList();
var viewModel = new ListUserViewModel { Users = users };
return View(viewModel);
}
}
Now use ListUserViewModel instead of User in your view as a model
#model Community.Models.ListUserViewModel
and the drop down
#Html.DropDownListFor(m => m.Users, new SelectList(Model.Users, "user_id", "name"), " ")
Explanation:
You are creating drop down list for Users with Model.Users as select list data source. "user_id" as a value of the selected user and "name" as display label. the last argument( i put empty string " ") is a default value that the drop down will display before selection.
I hope this will help you or someone else.

Try this,
model
public string CoutryID { get; set; }
public List<SelectListItem> CountryList { get; set; }
Controller method which fill the list
public List<Country> getCountryList()
{
using (QRMG_VendorPortalDataContext _context = new QRMG_VendorPortalDataContext())
{
return (from c in _context.Countries
where c.IsDeleted == false
select c).ToList();
}
}
Drop down list in View
#Html.DropDownListFor(m => m.CoutryID,
new SelectList(Model.CountryList,
"CoutryID", "Value"))

I find this system works (and avoids using ViewBag):
View Model:
public class YourViewModel
{
// This could be string, int or Guid depending on what you need as the value
public int YourDropdownSelectedValue { get; set; }
public IEnumerable<SelectListItem> YourDropdownList { get; set; }
}
Controller:
// Get database values (by whatever selection method is appropriate)
var dbValues = db.YourEntity.ToList();
// Make Selectlist, which is IEnumerable<SelectListItem>
var yourDropdownList = new SelectList(dbValues.Select(item => new SelectListItem
{
Text = item.YourSelectedDbText,
Value = item.YourSelectedDbValue
}).ToList(), "Value", "Text");
// Assign the Selectlist to the View Model
var viewModel = new YourViewModel(){
// Optional: if you want a pre-selected value - remove this for no pre-selected value
YourDropdownSelectedValue = dbValues.FirstOrDefault(),
// The Dropdownlist values
YourDropdownList = yourDropdownList
};
// return View with View Model
return View(viewModel);
and in the View:
#Html.DropDownListFor(a => a.YourDropdownSelectedValue, Model.YourDropdownList, "select this text - change this to null to exclude", new { #class = "your-class" })

If you are really new to ASP.Net MVC, this is a quite good Tutorial that shows you how the MVC-Pattern works.
MVC3: http://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/intro-to-aspnet-mvc-3
MVC4: http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/intro-to-aspnet-mvc-4
Here is the sample-code to download: http://code.msdn.microsoft.com/Introduction-to-MVC-3-10d1b098
this is an helpful video: http://www.asp.net/mvc/videos/mvc-1/conference-presentations/creating-nerddinnercom-with-microsoft-aspnet-model-view-controller-mvc

this is my table in the database
take look it my Action controller
// GET: Letters
public ActionResult Index()
{
ViewBag.LetterStatus = new SelectList(LetterStatusService.GetAllLettersStatus(), "Id", (CultureHelper.GetCurrentCulture() == "ar") ? "NameArabic" : "Name", Request.QueryString["LetterStatus"]);
return View();
}
and in the view
#Html.DropDownList("LetterStatus")
the constructor I used is
new SelectList(
list<Objlect> myListFromDatabase,
string PropertyNameOfValueInHtml,
string PropertyNameOfDesplayInHtml,
string SelectedItemValue
);
this line Request.QueryString["LetterStatus"] because I send the Selected Items within QuerySrting
and based on CurrentCulture I chose what column to display
and the result are
but I think the best way to do this,,,, is to get or create the Items then Iterate throw them to generate the select tag manually. I described this approach well in this answer
hope this helps you

I had to put Everything together from about 5 different Stack Overflow entries. I'm a newbie that's not in love with EF. I prefer doing things in SQL. Mike Perrenoud got me started, but I had trouble getting his solution to compile properly in the view.
First, I declared my dropdown Id/Name inside my model and then declared a numeric selector plus a SelectList
public class BusinessType
{
public int Id { get; set; }
public string Name { get; set; }
}
public int SelectedBusinessId { get; set; }
public SelectList BusinessTypeddList { get; set; }
In my [HttpGet] (the one that does not pass in a model), I ALWAYS populate my dropdowns. I'm doing things in SQL Server because I find it easier than the EF abstraction and syntax (which baffles me). This code declares a List of business types and populates it directly from the database. Feel free to use a sproc or whatever. IMPORTANT: Don't forget to return the View(model) at the end or your View will get an object missing reference error.
var list = new List<MerchantDetail.BusinessType>();
using (var con = new SqlConnection(Common.DB_CONNECTION_STRING_BOARDING))
{
con.Open();
using (var command = new SqlCommand("SELECT Id, BusinessTypeDesc as Name FROM BusinessType order by Id", con))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
list.Add(new MerchantDetail.BusinessType
{
Id = reader.GetInt32(0),
Name = reader.GetString(1)
});
}
}
}
}
var model = new MerchantDetail();
model.BusinessTypeddList = new SelectList(list, "Id", "Name");
model.SelectedBusinessId = 0;
return View(model);
The view is simple. Mine looks like this.
#Html.DropDownListFor(m => m.SelectedBusinessId, Model.BusinessTypeddList, "Select One:", new { #class = "custom-select" });
NOTE: Setting the SelectedBusinessId to 0 only works if there's nothing in the model. It will be set to one of the dropdown values otherwise. That will happen in a different HttpGet that passes the model in.

Related

C# Is it possible to model bind multiple options?

I have a dropdown on which you can select multiple options.
The code for this dropdown is:
How can i bind multiple 'devices' in C# so that when this dropdown is loaded
model binding will automatically select all options which are passed into the view?
For your case you should use another helper - #Html.ListBoxFor it should generate select element with multiple attribute.
//note that i use MaintanceDevices property
#Html.ListBoxFor(x => x.MaintanceDevices, new SelectList(Model.Devises, "ID", "Description"), new { #class = "multiselect form-control"})
Also, don't set id attribute in helper. It's better to create another property in your ViewModel:
public List<int> MaintanceDevices { get; set; }
Populate it in Controller and MVC automatically generate right markup for your select element bind in on form POST.
In this situations, i would do the following inside the viewmodel
public string Devices { get; set; }
List<int> innerList;
public List<int> List
{
get
{
if (this.innerList == null)
{
if (string.IsNullOrEmpty(this.Devices))
{
this.innerList = this.Devices.Split(',').Select(x => int.Parse(x)).ToList();
}
else
{
this.innerList = new List<int>();
}
}
return this.innerList;
}
}
Where Devices is the binded property with the dropdown, which it returns all items separated by ,.
When you try to access List it will separate the items and return it as a List<int>.
And i'm parsing it to int because normally i see int's as ID's
But i'm looking forward for a better option.
PS
I do this when working with Select2
Devices property in your model should be a list of Ids (where is a simple type like int or a string) and not a list of Device models (Since you are using new SelectList(Model.Devices, "ID", "Description") in the Helper it is i see that Model.Devices is a collection of complex object)
So your model should look like:
public List<Device> AvailableDevices { get;set; }
public List<string> Devices { get;set; }
and the Helper should be
#Html.ListBoxFor(m=>m.Devices,new SelectList(Model.AvailableDevices , "ID", "Description"))
or
#Html.DropDownListFor(m=>m.Devices,new SelectList(Model.AvailableDevices , "ID", "Description", new {multiple="multiple"})
post action should receive either a List<string> as an argument or a full model:
[HttpPost]
public ActionResult Submit(List<string> devices)
or
[HttpPost]
public ActionResult Submit(YourModel model)
//where YourModel model is the same type that you are using to render your view

Pass complex object in RedirectToAction MVC

I know this question has been asked several times and answered, but none of the solutions are working for me.
This is my ViewModel:
public class FlightSearchResults
{
public FlightSearch SearchModel { get; set; }
public List<vwLowFareSearchResults> SearchResults { get; set; }
public string TestString { get; set; }
public DateTime TestDate { get; set; }
}
I am using a RedirectToAction like this:
FlightSearchResults flightSearchResults = new FlightSearchResults();
flightSearchResults.SearchModel = model;
flightSearchResults.SearchResults = flights;
flightSearchResults.TestDate = DateTime.Now.AddDays(-2);
flightSearchResults.TestString = "Just Testing . . .";
return RedirectToAction("index", "flights", flightSearchResults);
I am only getting this List<vwLowFareSearchResults> SearchResults property in my flights index, none of the others are having values assigned. I have tried several variations from some threads on StackOverFlow like:
return RedirectToAction("index", "flights", new { SearchResults = flights, SearchModel = model });
return RedirectToAction("Result", "Dialog", new RouteValueDictionary(flightSearchResults));
I can return the view like this:
return View("~/Views/Flights/Index.cshtml", flightSearchResults);
but this is not a good solution as the url is not updated. I am modifying some older projects and it's mess of using Session and Viewbag.
I need to simplify and the pattern of view and controller communication of data in the previous code is a mess. Is it possible to do this without using the ViewData or Viewbag in a simple RedirectToAction.
Any kind of help in achieving this will be great as I am new to MVC.
Here is an approach I used recently. Try:-
... Previous code omitted.
//In your controller action, save the data to TempData...
TempData["FlightSearchResults"] = FlightSearchResults;
return RedirectToAction("flights");
}
public ActionResult flights()
{
FlightSearchResults flightResults = TempData["FlightSearchResults"];
return View(flightResults);
}
I actually used NewtonSoft to serialise the objects to a string, and then back again in the target action. So you might want to try something like ...
using Newtonsoft.Json;
...
...
... Previous code omitted.
//In your controller action, save the data to TempData...
TempData["FlightSearchResults"] = JsonConvert.SerializeObject(FlightSearchResults);
return RedirectToAction("flights");
}
public ActionResult flights()
{
string storedResults = TempData["FlightSearchResults"].ToString();
FlightSearchResults flightResults = JsonConvert.DeserializeObject<FlightSearchResults>(storedResults);
return View(flightResults);
}

persisting dropdownlist between mvc post if the ModelState is Invalid

I have a simple form which saves the following entity
public class TravelInfo{
public int ID {get;set;}
public string CentreCode {get;set;}
public DateTime TravelDate {get;set;}
}
I have the standard 2 create methods in my controller - 1 get 1 post and am using this viewmodel to get stuff into the view.
public class TravelInfoVM{
public TravelInfo TravelInfo{get;set;}
public IEnumerable<SelectListItem> Centres {get;set;}
}
Controller methods...
public ActionResult Create(){
var CentresList = db.Centres.Select(c=> new SelectListItem {Text = c.Name, Value = c.Code}).ToList();
TravelInfoVM = new TravelInfoVM(){Centres = CentresList};
return View(TravelInfoVM);
}
[HttpPost]
public ActionResult Create(TravelInfoVM model){
//the Centres part of the model at this point is empty
if(ModelState.IsValid){
//save
//redirect
}
//do i **REALLY** have to get it again as below, or can I hold on to it somehow?
model.Centres = db.Centres.Select(c=> new SelectListItem {Text = c.Name, Value = c.Code}).ToList();
return View(model);
}
the question is, do I really need to do a second round trip to the DB to get the list of Centres if the ModelState comes back as invalid? or is there a better/different way to persist this list across posts, until the user correctly enters the details required to save..? or do i have completely the wrong end of the stick..
Not without adding it to the session, which is an inappropriate use of the session. Otherwise, each request is a unique snowflake, even if it seems like it's the same because you're returning the same form with errors.
I wouldn't worry about this. It's just one query, and since it's the same query already issued previously, it will very likely (or at least could be) cached, so it may not actually hit the database, anyways.
One thing I would recommend though is abstracting the query so that your GET and POST actions will simply call a function that won't change, and if you need to make a change to how the select list is created, you just do it in one place:
internal void PopulateCentreChoices(TravelInfoVM model)
{
model.Centres = db.Centres.Select(c=> new SelectListItem {Text = c.Name, Value = c.Code}).ToList();
}
...
public ActionResult Create(){
var model = new TravelInfoVM();
PopulateCentreChoices(model);
return View(model);
}
[HttpPost]
public ActionResult Create(TravelInfoVM model){
if(ModelState.IsValid){
//save
//redirect
}
PopulateCentreChoices(model);
return View(model);
}

using ViewBag to pass a model object

I'm trying to sort my result page (which is in another view than the filtration page). I have faced this weird issue I do not understand why keeps happening to me.
All the codes provided in very short form, please ask me if you need any other parts of my code for more information.
My Index view(where user filters results):
#model IEnumerable<Cars.Models.CarSearch>
#using (Html.BeginForm("SearchResult", "Home", FormMethod.Post,
new
{
id = "CategoryFormID",
data_modelListAction = #Url.Action("ModelList"),
data_makeListAction = #Url.Action("MakeList"),
data_editionListAction = #Url.Action("EditionList")
}))
{
<label>Make</label>
<select id="MakeID" name="carMake">
<option>All Makes</option>
</select>
}
My SearchResult view:
#model IEnumerable<Cars.Models.Car>
Make
My model:
public class Car
{
public String Make { get; set; } //is my table model
}
public class CarFilter {
public String carMake { get; set; }
}
public class CarSearch {
public CarFilter CarFilter { get; set; }
public byte PageSize { get; set; }
public short PageNumber { get; set; }
public int TotalRows { get; set; }
}
My Controller:
public ActionResult SearchResult(String sortOrder, CarFilter filters)
{
ViewBag.CurrentFilters = filters;
return View();
}
All I'm trying to do is to get carMake from Index post it to controller in CarFilter form (since in my code there are LOTS of fields in the form and I don't want to write them all down) and when user clicks on sort by Make it GET the SearchResult method and it's supposed to set filters = ViewBag.CurrentFilters which is the value user inputted from beginning.
Now the funny part is, when I replace CarFilter filters with String carMake and other places respectively. It works like a charm.
My question:
Why?
How can I do this with CarFilter filters?
UPDATE:
Problem is that filters = ViewBag.CurrentFilters in my SearchResult view does not work with the type CarFilter, because it keeps giving me NULL value when user clicked on the sort by Make.
Second UPDATE:
I tried changing filters = ViewBag.CurrentFilters with CarFilter = ViewBag.CurrentFilters. Now CarFilter filters in my SearchResult(...)method in my controller is not and null object, but ALL the values of the objects in the model class is null (which shouldn't be). I mean the filters object exists but it seems like the values of CarFilter class in my model haven't been passed by ViewBag.CurrentFilters to the view.
when you canged the name it worked because framework found property name and the bind it to what you have within action parameters doesnt work so nicely with objects. My advice is to stick with simple types
Here is similiar case:
How to send model object in Html.RenderAction (MVC3)
Its not a ViewBag problem thants how it works in general. Its the prime reason for using flatted models :/

How do I transfer ViewModel data between POST requests in ASP.NET MVC?

I have a ViewModel like so:
public class ProductEditModel
{
public string Name { get; set; }
public int CategoryId { get; set; }
public SelectList Categories { get; set; }
public ProductEditModel()
{
var categories = Database.GetCategories(); // made-up method
Categories = new SelectList(categories, "Key", "Value");
}
}
Then I have two controller methods that uses this model:
public ActionResult Create()
{
var model = new ProductEditModel();
return View(model);
}
[HttpPost]
public ActionResult Create(ProductEditModel model)
{
if (ModelState.IsValid)
{
// convert the model to the actual entity
var product = Mapper.Map(model, new Product());
Database.Save(product);
return View("Success");
}
else
{
return View(model); // this is where it fails
}
}
The first time the user goes to the Create view, they are presented with a list of categories. However, if they fail validation, the View is sent back to them, except this time the Categories property is null. This is understandable because the ModelBinder does not persist Categories if it wasn't in the POST request. My question is, what's the best way of keeping Categories persisted? I can do something like this:
[HttpPost]
public ActionResult Create(ProductEditModel model)
{
if (ModelState.IsValid)
{
// convert the model to the actual entity
var product = Mapper.Map(model, new Product());
Database.Save(product);
return View("Success");
}
else
{
// manually populate Categories again if validation failed
model.Categories = new SelectList(categories, "Key", "Value");
return View(model); // this is where it fails
}
}
But this is an ugly solution. How else can I persist it? I can't use a hidden field because it's a collection.
I would use the repository to fetch whatever data is needed and don't think it's an ugly solution:
[HttpPost]
public ActionResult Create(ProductEditModel model)
{
if (!ModelState.IsValid)
{
// manually populate Categories again if validation failed
model.Categories = Repository.GetCategories();
return View(model);
}
// convert the model to the actual entity
var product = Mapper.Map(model, new Product());
Database.Save(product);
// I would recommend you to redirect here
return RedirectToAction("Success");
}
To further refactor this I would recommend you watching the excellent Putting Your Controllers on a Diet video presentation by Jimmy Bogard.
I typically implement my lists (for drop downs) as a readonly property. When the View gets the value the property is self contained on what it needs to return the values.
public SelectList Categories
{
get
{
var categories = Database.GetCategories(); // made-up method
return new SelectList(categories, "Key", "Value");
}
}
If necessary you can grab the currently selected item (i.e. validation failed) from the property containing the id that was posted and bound to the instance of your class.
In my case I have a BaseModel class where I keep all those property list as class attributes.
Like in the following sample:
public IEnumerable<SelectListItem> CountryList
{
get
{
return GetCountryList().Select(
t => new SelectListItem { Text = t.Name, Value = Convert.ToString(t.CountryID) });
}
}
GetCountryList() is a function that ask a Singleton for data. This would only happen once in the app lifecycle
Another way for doing this, and if those lists are pretty big, would be to have a static utility class with the lookup table that returns the SelectListItem.
If you need to access a list that change from time to time then simply dont use a Singleton class.

Categories

Resources