When using DropDownListFor how do I bind the SelectList to the Model - asp.net-mvc-3

This page works in two steps,
Step 1 - The user hits Index() and the SelectList is populated with the applications from the databse.
Step 2 - they select an applicaiton from the list, which posts the page back, which reloads the page with the application Details added
Error: When I run this and get to step 2, I get an error back saying:
The ViewData item that has the key 'ApplicationId' is of type 'System.Int32' but must be of type 'IEnumerable'.
This appears to be because the Model.ApplicationList is now null as it hasn't bound back to the model when the form was posted, can I make it do this?
View:
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.ApplicationId, Model.ApplicationList, "Select an Application" , new { #onchange = "this.form.submit();" })
}
Model:
public class IndexModel
{
public int ApplicationId { get; set; }
public List<SelectListItem> ApplicationList { get; set; }
public string Detail { get; set}
}
Controller:
public ActionResult Index()
{
using (var dc = new Entities())
{
var model = new IndexModel();
model.ApplicationList = new List<SelectListItem>();
var applications = dc.Applications.OrderBy(a => a.Name).ToList();
foreach (var application in applications)
{
model.ApplicationList.Add(new SelectListItem
{
Selected = false,
Text = application.Name,
Value = application.Id.ToString()
});
}
model.ApplicationId = 1;
return View(model);
}
}
[HttpPost]
public ActionResult Index(IndexModel model)
{
model.Detail = GetDetail(model.ApplicationId);
return View(model);
}

I was struggling with the same problem. It doesn't look like .net mvc3 lets you do this without the help of jquery. Drop down lists will get their selected item bound to the model when posting but not all the items in the combo box. You would have to rebuild it each time you pass the viewmodel back to the view.
Another way around losing the dropdown list is to use ajax.

Related

I can't fetch data from the db with a Html.DropDownListFor, in MVC 4 (or 5)

I have read some pages regarding DDls, but I can't get my DDLF (DropDownListFor) to work. I have a model, and a db, but I don't know how I can in the view show one DDLF.
What I get to work, is this code:
#foreach (var item in Model)
{
#Html.DropDownListFor(m => item.Id,
new SelectList(ViewBag.SjukhusDropDownList),
"Choose something")
}
But then I get several DDLs. And I don't know how to insert data into them, so the data to the user will get fetched from the db. Like sending an id with something to the action, to do something with it. But here, I can only click on anything in the list, but of course, nothing will happen since I haven't bound any data to any option in that select list.
Here's an example for DropDownListFor in MVC 4
In the model create two properties, one for the list itself and one for identifying the list entries. In this example the vu-number identifies a merchant:
public class MyModel
{
[Display(Name = "VU")]
public string vu{ get; set; }
public List<SelectListItem> merchantList{ get; set; }
}
Initialize and load model data in the Http GET method of the controller:
public ActionResult ShowMerchants()
{
MyModel model = new MyModel();
model.merchantList = GetMerchants();
model.vu = model.merchantList[0].Value;
return View(model);
}
Create the list items using some rows from database. I.e. you can use TableAdapter and DataTable to achieve it:
private List<SelectListItem> GetMerchants()
{
List<SelectListItem> merchantList = new List<SelectListItem>();
MyDataSet.viewVUDataTable myDataTable = new MyDataSet.viewVUDataTable();
MyDataTableAdapters.VUListTableAdapter myTableAdapter = new MyDataTableAdapters.VUListTableAdapter();
myTableAdapter.Fill(myDataTable);
// iterate over rows in datatable
for(int i=0; i< myDataTable.Rows.Count; i++)
{
// Text is shown in the dropdownlist
// Value is used to identify the selected item
merchantList.Add(
new SelectListItem { Text = myDataTable[i].text, Value = myDataTable[i].vu});
}
return merchantList;
}
and in the view:
#Html.DropDownListFor(
model => model.vu,
Model.merchantList,
new { #class = "form-control" })

ASP.NET MVC 4 Want to populate dropdown list from database

I am new guy in ASP.NET MVC 4. I want to populate dropdownlist from database table BO where Column name is Id, Code, Name, OrgId. I want to bind two Code & Namecolumn's data to DataTextfield and Id column Data to DataValueField of dropdown. I have created code for this which are as follows BUT ITS NOT RETURNING DATA FROM TABLE and var BOList is remain empty :
my connectionstring is
<add name="iRegDBContext"
connectionString="Data Source=****;Initial Catalog=iReg;User ID=**;Password=****;Integrated Security=True"
providerName="System.Data.SqlClient"
/>
My Controller class :
public class iRegController : Controller
{
private iRegDBContext l_oDbBO = new iRegDBContext();
// GET: /iReg/
public ActionResult PopulatejQgrid()
{
var BOList = l_oDbBO
.BO
.ToList()
.Select(d => new SelectListItem
{
Value = d.Id.ToString(),
Text = d.Name + "[ " + d.Code + " ]"
});
ViewBag.BOData = new SelectList(BOList, "Value", "Text");
return View();
}
}
My Model class :
public class BO
{
public Guid Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
public class iRegDBContext : DbContext
{
public DbSet<BO> BO { get; set; }
}
My cshtml class :
#model MvciReg.Models.BO
#{
ViewBag.Title = "PopulatejQgrid";
}
#using (Html.BeginForm())
{
<fieldset>
BO :
#Html.DropDownList("BOData")
<p>
<input type="submit" value="Go" />
</p>
</fieldset>
}
I really don't know where I am going wrong. I developed my code from reference of following link Click here . Kindly suggest correction in code ...
UPDATE: I tried following Matt Bodily's code in my controller and what I see is code is not fetching data from database and that code is
public ActionResult populatejQgrid()
{
ViewBag.BOData = GetDropDown();
return View();
}
public static List<SelectListItem> GetDropDown()
{
List<SelectListItem> ls = new List<SelectListItem>();
var lm = from m in db.BOs //fetch data from database
select m;
foreach (var temp in lm)
{
ls.Add(new SelectListItem() { Text = temp.Name, Value = temp.Id.ToString() });
}
return ls;
}
In Controller :
#Html.DropDownList("BOData", (List<SelectListItem>)ViewBag.BOData)
But when I saw value of ls through watch it always show me Count = 0 but its not giving me any error.
I found something new this problem. When I kept mouse pointer over var lm; it shows me query and in query table name in FROM clause is not that one in my SQL database. My SQL table name is BO and in query it is taking BOes. I don't know from where this name is coming. I think this is the main cause of all this problem So How I overcome this??
First Create a BO list for Dropdownlist in VIEW
#{
var Bolst= Model.BO.Select(cl => new SelectListItem
{
Value = cl.Value.ToString(),
Text = cl.Text== null ? String.Empty : cl.Text
});
}
#(Html.DropDownList("sampleDropdown", BOlst, "-----Select-----"))
In Controller:
return View(BOlst); // why use Viewbag when directly pass it to view
from what I see in your code you are creating the select list and setting the ViewBag.BOData on the controller.
So in order to render it on the view you should do this
#Html.DropDownList(ViewBag.BOData)
instead of
#Html.DropDownList("BOData")
Regarding the access to the database are you trying to use "code first" in an existing database?
If you are you need to override the context constructor like this
public class iRegDBContext : DbContext
{
  public iRegDBContext()
     :base("Name= iRegDBContext")
   {
   }
}
see this link http://msdn.microsoft.com/en-us/data/jj200620.aspx
Hope it helps.
try building your dropdown this way
#Html.DropDownList(x => x.Selected, PathToController.GetDropDown())
and then in your controller
public static List<SelectListItem> GetDropDown()
{
List<SelectListItem> ls = new List<SelectListItem>();
lm = (call database);
foreach (var temp in lm)
{
ls.Add(new SelectListItem() { Text = temp.name, Value = temp.id });
}
return ls;
}
Hopefully this helps
I recently had this issue also and managed to get it working using Viewbag. You will need to make it fit your Db tables but it works and is quite simple.
Populating Drop Down Box with Db Data

There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'SelectedCityName'

I am populating DropDownList in View and getting this error on POST.
Error:
There is no ViewData item of type 'IEnumerable' that has the key 'SelectedCityName'.
Controller:
public ViewResult Register()
{
var Cities = ILocaRepo.Cities.ToList();
var Wards = ILocaRepo.Wards.ToList() ;
var model = new RegisterViewModel
{
City = Cities.Select(x => new SelectListItem
{
Value = x.CityID.ToString(),
Text = x.CityName
}),
Ward = Wards.Select(x => new SelectListItem
{
Value = x.WardID.ToString(),
Text = x.WardName
})
};
return View(model);
}
//
// POST: /Account/Register
[HttpPost]
public ActionResult Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
MembershipService.CreateUser(model.User.Username, model.User.Password, model.User.Name, model.SelectedCityName, model.SelectedWardName, model.User.Address, model.User.Phone, model.User.Email, "Member");
FormsAuthentication.SetAuthCookie(model.User.Username, false);
return RedirectToAction("ListProduct", "Product");
}
catch (ArgumentException ae)
{
ModelState.AddModelError("", ae.Message);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
View :
<tr>
<td class="info_label">City</td>
<td>#Html.DropDownListFor(m=>m.SelectedCityName,Model.City,"-- Chọn thành phố --",new { #class = "dropdown" })</td>
</tr>
<tr>
<td class="info_label">Ward</td>
<td>#Html.DropDownListFor(m => m.SelectedWardName, Model.Ward, "-- Chọn quận --", new { #class = "dropdown" })</td>
</tr>
And the ViewModel:
public User User { get; set; }
public string SelectedCityName { get; set; }
public string SelectedWardName { get; set; }
public IEnumerable<SelectListItem> City { get; set; }
public IEnumerable<SelectListItem> Ward { get; set; }
How can i get SelectedCityName to pass as parameter of RegisterUser method?. Any help is appreciated.
Inside your POST action you are rendering the same view in case of error (return View(model);). But you forgot to assign the City and Ward properties, the same way you did in your GET action and they will be null when this view is rendered.
So:
// If we got this far, something failed, redisplay form
// and don't forget to rebind City and Ward
model.City = ILocaRepo.Cities.ToList().Select(x => new SelectListItem
{
Value = x.CityID.ToString(),
Text = x.CityName,
});
model.Ward = ILocaRepo.Wards.ToList().Select(x => new SelectListItem
{
Value = x.WardID.ToString(),
Text = x.WardName,
});
// Now we can safely redisplay the same view
return View(model);
The reason why those 2 properties are null inside your POST action is pretty simple and lies into the design of HTML forms. In HTML when you submit a form containing a <select> element (which is what those Html.DropDownListFor helpers are generating), only the selected value is sent to the server. The list of available values is not sent to the server simply because it is assumed that you already have it somewhere on the server (because you rendered this form in the first place). So it is your responsibility, if you decide to redisplay the form in your POST action, to re-populate those collections in order to be able to display the dropdown lists properly.

MVC3 Persisting data from controller to view back to controller

I have a model containing a couple of lists:
[Display(Name = "Facilities")]
public List<facility> Facilities { get; set; }
[Display(Name = "Accreditations")]
public List<accreditation> Accreditations { get; set; }
I populate these lists initially from my controller:
public ActionResult Register()
{
var viewModel = new RegisterModel();
viewModel.Facilities = m_DBModel.facilities.ToList();
viewModel.Accreditations = m_DBModel.accreditations.ToList();
return View(viewModel);
}
When they get to my view they are populated with the DB records (great). I then pass the model to the partial view which displays these lists as checkboxes, ready for user manipulation (I have tried based on another suggestion using for loop instead of foreach loop, made no difference):
#model LanguageSchoolsUK.Models.RegisterModel
#foreach (var item in Model.Facilities)
{
#Html.Label(item.name);
#Html.CheckBox(item.name, false, new { id = item.facility_id, #class = "RightSpacing", #description = item.description })
}
When I submit the form and it ends up back at my controller this time calling the overloaded register function on the controller:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Do stuff
}
return View(model);
}
The problem is that the model parameter containing the lists (Facilities and Accreditations) is telling me that the lists are null.
Please can somebody tell me what I am doing wrong, why aren't they populated with the collections that I originally passed through and hopefully a way of asking whick ones have been checked?
Thanks.
I have tried based on another suggestion using for loop instead of
foreach loop, made no difference
Try again, I am sure you will have more luck this time. Oh and use strongly typed helpers:
#model LanguageSchoolsUK.Models.RegisterModel
#for (var i = 0; i < Model.Facilities.Count; i++)
{
#Html.HiddenFor(x => x.Facilities[i].name)
#Html.LabelFor(x => x.Facilities[i].IsChecked, Model.Facilities[i].name);
#Html.CheckBoxFor(
x => x.Facilities[i].IsChecked,
new {
id = item.facility_id,
#class = "RightSpacing",
description = item.description // <!-- HUH, description attribute????
}
)
}
Also you will undoubtedly notice from my answer that checkboxes work with boolean fields on your model, not integers, not decimals, not strings => BOOLEANS.
So make sure that you have a boolean field on your model which will hold the state of the checkbox. In my example this field is called IsChecked but obviously you could feel absolutely free to find it a better name.

ASP.NET MVC 3 Viewmodel Pattern

I am trying to work out the best way of using a viewmodel in the case of creating a new object.
I have a very simple view model that contains a contact object and a select list of companies.
private ICompanyService _Service;
public SelectList ContactCompanyList { get; private set; }
public Contact contact { get; private set; }
public ContactCompanyViewModel(Contact _Contact)
{
_Service = new CompanyService();
contact = _Contact;
ContactCompanyList = GetCompanyList();
}
private SelectList GetCompanyList()
{
IEnumerable<Company> _CompanyList = _Service.GetAll();
return new SelectList(_CompanyList, "id", "name");
}
I then have contact controller that uses this viewmodel and enable me to select a related company for my contact.
[Authorize]
public ActionResult Create()
{
return View(new ContactCompanyViewModel(new Contact()));
}
My issue is with the create method on the controller.
[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Contact _Contact)
{
try
{
_Service.Save(_Contact);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
The problem is that the view returns an empty contact object, but! the company id is populated, this is because the dropdown list explicitly declares its field name.
#Html.DropDownList("parent_company_id",Model.ContactCompanyList)
The standard html form fields pass the objects values back in the format of contact.forename when using the HTML.EditorFor helper...
#Html.EditorFor(model => model.contact.forename)
I can access them if I use a FormCollection as my create action method paremeter and then explicitly search for contact.value but I cannot use a Contact object as a parameter to keep my code nice and clean and not have to build a new contact object each time.
I tried passing the actual view model object back as a parameter but that simply blows up with a constructor error (Which is confusing seeing as the view is bound to the view model not the contact object).
Is there a way that I can define the name of the Html.EditFor field so that the value maps correctly back to the contact object when passed back to the create action method on my controller? Or Have I made some FUBAR mistake somewhere (that is the most likely explanation seeing as this is a learning exercise!).
Your view model seems wrong. View models should not reference any services. View models should not reference any domain models. View models should have parameterless constructors so that they could be used as POST action parameters.
So here's a more realistic view model for your scenario:
public class ContactCompanyViewModel
{
public string SelectedCompanyId { get; set; }
public IEnumerable<SelectListItem> CompanyList { get; set; }
... other properties that the view requires
}
and then you could have a GET action that will prepare and populate this view model:
public ActionResult Create()
{
var model = new ContactCompanyViewModel();
model.CompanyList = _Service.GetAll().ToList().Select(x => new SelectListItem
{
Value = x.id.ToString(),
Text = x.name
});
return View(model);
}
and a POST action:
[HttpPost]
public ActionResult Create(ContactCompanyViewModel model)
{
try
{
// TODO: to avoid this manual mapping you could use a mapper tool
// such as AutoMapper
var contact = new Contact
{
... map the contact domain model properties from the view model
};
_Service.Save(contact);
return RedirectToAction("Index");
}
catch
{
model.CompanyList = _Service.GetAll().ToList().Select(x => new SelectListItem
{
Value = x.id.ToString(),
Text = x.name
});
return View(model);
}
}
and now in your view you work with your view model:
#model ContactCompanyViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedCompanyId, Model.CompanyList)
... other input fields for other properties
<button type="submit">Create</button>
}

Resources