I have two classes many-to-many the first is "Anuncios" and the second "SubCategorias"
public class Anuncios {
public int AnuncioId {get;set;}
public string Titulo {get;set;}
public ICollection<SubCategorias> SubCategorias {get;set;}
}
public class SubCategorias {
public int SubCategoriaId {get;set;}
public string Nome {get;set;}
public ICollection<Anuncios> Anuncios {get;set;}
}
In DAL layer I did method to save the "Anuncio" in DB.
public void Salvar(Anuncio entidade) {
entidade.SubCategorias = entidade.SubCategorias.Select(subcat => _contexto.SubCategorias.FirstOrDefault(x => x.SubCategoriaId == subcat.SubCategoriaId)).ToList();
_contexto.Anuncios.Add(entidade);
_contexto.SaveChanges();
}
I Create the Action "Create":
private readonly Context _ctx = new Context();
public ActionResult Create()
{
var model = new Anuncios {SubCategorias = _ctx.SubCategorias.ToList()};
return View(model);
}
In View I made DropDownList with "SubCategorias":
#Html.LabelFor(model => model.SubCategorias)
#Html.DropDownListFor(model => model.SubCategorias, new SelectList(Model.SubCategorias, "SubCategoriaId", "Nome"))
The DropDownListFor is populated with sucess..
Fine....
But when submit form the value selected in DropDownListFor not pass to method Create. The anuncio.SubCategorias is null!
private readonly AnunciosDal _anuncio = new AnunciosDal();
[HttpPost]
public ActionResult Create(Anuncio anuncio)
{
_anuncio.Salvar(anuncio);
return View(anuncio);
}
I have sought in various forums the solution, but could not find
Somebody help me?!
Sorry about my english rs...
Thank You!
Fabrício Oliveira
The first parameter of DropDownListFor needs to be the object holding the selected value, where the second parameter contains the list:
#Html.DropDownListFor(model => model.SOME_ID_FOR_SELECTED_VALUE,
new SelectList(Model.SubCategorias, "SubCategoriaId", "Nome"))
Currently the example you have also maps the same list as the first property. You should use an ID like #Maess suggested, and then bind it via:
#Html.DropDownListFor(model => model.SubCategoriaID, new SelectList(Model.SubCategorias, "SubCategoriaId", "Nome"))
Selecting a value will then post it back to the server to this SubCategoriaID field.
You need to have another property to store the selected value from the dropdown. It is best if you create a viewmodel with properties which are needed for your view.
public class CreateAnuncios
{
public string Title {set;get;}
public int SelectedSubCategoryId {set;get;}
public List<SelectListItem> SubCategories {set;get;}
public CreateAnuncios()
{
this.SubCategories = new List<SelectListItem>();
}
}
Now in your create action, create an object of this view model, Fill the SubCategories property and send to the view.
public ActionResult Create()
{
var vm=new CreateAnuncios();
vm.SubCategories = ctx.SubCategorias
.Select(s=> new SelectListItem
{ Value = s.SubCategoriaId .ToString(),
Text=s.Nome}).ToList();
return View(vm);
}
Your create view should be strongly typed to the CreateAnuncios class
#model YourNameSpaceHere.CreateAnuncios
#using(Html.Beginform())
{
#Html.TextBoxFor(s=>s.Title)
#Html.DropdownListFor(s=>s.SelectedSubCategoryId,Model.SubCategories,"Select")
<input type="submit" />
}
Now when user posts the form, Read the Properties of the posted model and use that to save to db.
[HttpPost]
public ActionResult Create(CreateAnuncios model)
{
//Check for model.Title and model.SelectedSubCategoryId and use it to save
// to do :Save and redirect
}
You need to provide a collection of SelectListItems that populate your DropDownList as well as a property to hold the currently selected SelectListItems' Id (which will be posted back to the server):
public class Anuncios {
public int AnuncioId {get;set;}
public string Titulo {get;set;}
public ICollection<SubCategorias> SubCategorias {get;set;}
public int SelectedSubCategoryId {get;set;}
public IEnumerable<SelectListItem> SubCategoryListItems {get;set;}
}
then, present them to the user via:
#html.DropDownListfor(x => x.SelectedSubCategoryId, Model.SubCategoryListItems)
The SubCategoryListItems will have to be populated from the server, typically something like this:
this.SubCategoryListItems = this.SubCategorias.Select(x => new SelectListItem { Text = x.Name, Value = x.Id });
You need an id property for the SubCategoria you have it in your binding, but not in the model
public class Anuncios {
public int AnuncioId {get;set;}
public string Titulo {get;set;}
public ICollection<SubCategorias> SubCategorias {get;set;}
public int SubCategoriaId{get;set;}
}
Related
I'm trying to use SelectListItem for an MVC project, drop down is populated as I expect it. But when I pass the selected value to a function that accepts string using this model.CodeDropDown.ToString() I get System.Collections.Generic.List 1[System.Web.Mvc.SelectListItem] which is not a string.
How can I get the selected value as string?
I have a ViewModel class that looks like this:
public class HomeViewModel
{
[Required]
[DisplayName("Code")]
public IEnumerable<SelectListItem> CodeDropDown { get; set; }
public string SelectedValue { get; set; }
}
I'm filling up the dropdown using this Controller
public ActionResult Index()
{
var model = new HomeViewModel();
using (var dbCon = new SomeDBContext())
{
model.CodeDropDown = dbCon.CodeID.ToList().Select(x => new SelectListItem
{
Value = x.Name.ToString(), Text = x.CodeDropDown.ToString()
}).DistinctBy(c => c.Value);
}
return View(model);
}
}
I'm trying to use the value from SelectListItem like this,
public ActionResult Index(HomeViewModel model)
{
var results = mainDbContext.GetSomeResult(model.CodeDropDown.ToString(), model.Prop2, model.Prop3);
return View(results);
}
View looks like this:
#Html.DropDownListFor(model => model.SelectedValue, Model.CodeDropDown, "--")
Add one more property (SelectedThingId or something more meaningful) to your HomeViewModel to hold the value of the selected thing from the dropdown.
In your view (you have not posted code for view) have something like this:
#Html.DropDownListFor(x=>x.SelectedThingId, Model.CodeDropDown)
Then in your controller you can get this value using:
model.SelectedThingId; // model is passed into your controller has you have it.
Add 2 properties in the model
public string CodedropdownID{ get; set; } //to store the selected dropdown value Id
public string CodedropdownText{ get; set; } //to store the selected dropdown value text
Change the View as following and add onchange event to dropdown:
#Html.DropDownListFor(m=> m.CodedropdownID, m.CodeDropDown, "--")
#Html.Hiddenfor(m=>m.CodedropdownText)
Add the following script:
<script type="text/javascript">
$("#CodedropdownID").on("change", function {
$("#CodedropdownText").val($(this).text());
});
</script>
Change the controller method
public ActionResult Index(HomeViewModel model)
{
var results = mainDbContext.GetSomeResult(model.CodedropdownText.ToString(), model.Prop2, model.Prop3);
return View(results);
}
I would like to follow best MVC best practise for creating DropLists.
I have 3 Models (I have cut them down for the purposes of this)
Model One
Student
public int ID {get;set;}
public string Name {get;set}
public Site SiteID {get;set;}
Model Two
Site
public int ID {get;set;}
public string SiteName {get;set}
Model Three
VM
public int ID {get;set}
public student Students {get;set;}
public DateTime Date { get { return DateTime.Now; } }
public bool Criteria {get;set;}
In my VM view I am using EditorFor html helpers to populate my VM and Student Models. The site model is pre populated at the database seed.
I am looking for the best way to include a dropdownlist of sites on my VM view, that will map to my student model.
How to I correctly set up my models to achieve this?
In short, you want the DropDownListFor extension method and to put a List<Site> into the view model.
Here is a Fiddle that demonstrates your case. The Fiddle has more details. The nuts and bolts are here:
ViewModel - Add a List<Site>
public class MyViewModel
{
public MyViewModel()
{
this.Sites = new List<Site>();
}
public int ID { get; set;}
public Student Students { get; set; }
public DateTime Date { get { return DateTime.Now; } }
public bool Criteria { get; set; }
public List<Site> Sites { get; set; }
}
View - Use DropDownListFor
#Html.DropDownListFor(m => m.Sites,
new SelectList(Model.Sites, "ID", "SiteName"))
In psuedo-code, the above says
The Sites object in the model contains the properties to display.
Create a new SelectList using the Sites object in the model. Use the ID property as the data value and the SiteName property as the data text.
Create a drop down list based on the above info.
Controller
This just passes a seeded view model to the view.
public ActionResult Index()
{
var vm = SeedFromDatabase();
return View(vm);
}
private MyViewModel SeedFromDatabase()
{
var vm = new MyViewModel();
vm.Sites.Add(new Site(0, "one"));
vm.Sites.Add(new Site(1, "two"));
vm.Sites.Add(new Site(2, "three"));
return vm;
}
ViewModel
public class VM
{
public int ID {get;set}
public student Students {get;set;}
public SelectList SiteList {get;set;}
public int SiteID {get;set;}
public DateTime Date { get { return DateTime.Now; } }
public bool Criteria {get;set;}
}
Load View Action
public ActionResult LoadVMView(){
var model = new VM();
var items = GetSitesFromDatabase().Select(s => new SelectListItem(){
Text = s.SiteName,
Value = s.ID.ToString()
});
model.SiteList = new SelectList(items);
return View(model);
}
View:
#Html.DropDownListFor(m => m.SiteID, Model.SiteList)
On Post
[HttpPost]
public ActionResult LoadVMView(VM model){
var selecteSiteID = model.SiteID;
}
Trying to unpack some inherited code and I am new to ASP.NET. My question:
What is available in the controller from a post action in a dropdownlist in C# (ASP.NET MVC5)?
Here is what I have in the view:
#using (Html.BeginForm("SignUp", "Location", FormMethod.Post))
....
#Html.DropDownListFor(
model => model.Member.PillarId, new SelectList (Model.Pillars, "Id", "Title"))
Here is the MemberViewModel:
public class MemberViewModel : IValidatableObject{
public int? LocationId { get; set; }
public int? PillarId { get; set; }
}
Here is the Member model:
public class Member
{
public int Id { get; set; }
public string Name { get; set; }
public int? LocationId { get; set; }
public int? PillarId { get; set; }
public String PillarTitle { get; set; }
Here is the Member model constructor(s):
public Member() { }
public Member(MemberViewModel member)
{
PillarId = member.PillarId;
///
}
Here is the Controller
public ActionResult SignUp(MemberViewModel member){///}
My form is correctly pulling the information from the DB to display, as well as posting correctly to the DB via the Controller. I do not want to change the visual options for the user to choose from (i.e. I think ListBox is out?).
Rather, I want to assign both Member.PillarId as well as the Member.Title based on their choice and have it available in the Controller for non-DB operations.
What is currently available in the SignUp method in the Controller? Can I call Model.Pillars.Title? Is it member.PillarId.Pillars.Id? If not, how can I assign it dynamically based on the user choice?
There are views and modelviews flying around in this code, and I am not sure what is available...
SO has a bunch of answers on the DropDownList, so here's a sampling of articles that are somewhat related to what I am getting at...
* This answer
* ListBox
* ListBoxFor: not MVC dynamic
* SelectList Constructor: Not MVC
With a dropdownlist the only value that will come back is the value of the selected item when posting back.
If you want something else to come back you would need a hidden field on the page and bind a change event listener to the dropdown to set the title in the hidden field
public class MemberViewModel : IValidatableObject{
public int? LocationId { get; set; }
public int? PillarId { get; set; }
public string Title { get; set;}
}
#using (Html.BeginForm("SignUp", "Location", FormMethod.Post))
....
#Html.DropDownListFor(
model => model.Member.PillarId, new SelectList (Model.Pillars, "Id", "Title"))
#Html.HiddenFor(model => model.Title);
javascript
$('#idofdropdown').on('change', function()
{
var selectedTitle = $(this).find(":selected").text();
$('#Title').val(selectedTitle);
});
How to get selected title from a drop down list: Get selected text from a drop-down list (select box) using jQuery
Then in your controller your viewmodel will have the title text inside the Title string :)
I have two models and I want to insert a row in the database with a foreign key relationship populated in the DropDownList. The Item model's data insert without problems but ManufacturerID does not get inserted (it inserts null). I could not find why.
Update: Uploaded the project to: http://mvcapplication2.codeplex.com/
<div class="editor-label">
#Html.LabelFor(model => model.ManufacturerID,"Manufacturer")
</div>
<div class="editor-field">
#Html.DropDownList("ManufacturerID",string.Empty)
#Html.ValidationMessageFor(model => model.ManufacturerID)
</div>
public class Item
{
public int ItemID { get; set; }
public string Serial { get; set; }
public string ItemName { get; set; }
public int? ManufacturerID { get; set; }
public Manufacturer Manufacturer { get; set; }
}
public class Manufacturer
{
public int ManufacturerID { get; set; }
public string ManufacturerName { get; set; }
public List<Item> Items { get; set; }
}
public ActionResult Create()
{
ViewBag.ManufacturerID = new SelectList(db.Manufacturers, "ManufacturerID", "ManufacturerName");
return View();
}
[HttpPost]
public ActionResult Create(Item ıtem)
{
if (ModelState.IsValid)
{
db.Items.Add(ıtem);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(ıtem);
}
I would prefer to NOT use the domain model in the view. I would create some view models specific to the view. Also, to transfer data from action method (ex : dropdown list), i would use a strongly typed approach, instead of the dynamic viewbag/ viewdata approach.
Create a view model class
public class CreateItemVM
{
public string SerialNumber { set;get;}
public int SelectedManufactureID { set;get;}
public List<SelectListItem> Manufacturers { set;get;}
public CreateItemVM()
{
Manufacturers =new List<SelectListItem>();
}
}
Now in your GET action method, create an object of our viewmodel, initialize the relevant values and send to the view.
public ActionResult Create()
{
var vm=new CreateItemVM();
vm.Manufacturers=GetManufacturerList();
return View(vm);
}
private List<SelectListItem> GetManufacturerList()
{
List<SelectListItem> manuList=new List<SelectListItem>();
manuList=(from p in db.Manufacturers
select new SelectListItem {
Value=p.ID.ToString(),
Text=p.Name}
).ToList();
return manuList;
}
Now in our view, which is strongly typed to our Viewmodel,
#model CreateItemVM
#using(Html.Beginform())
{
#Html.DropDownListfor(x=>x.SelectedManufactureID ,
Model.Manufacturers,"select")
<input type="submit" />
}
And finally in our POST action method, we will read values from our posted viewmodel and assign it as the property values of our domain object and save it. the selected manufacturers ID value will be in the SelectedManufactureID property of our viewmodel.
[HttpPost]
public ActionResult Create(CreateItemVM model)
{
if(ModelState.IsValid)
{
Item domainObject=new Item();
domainObject.ManufacturerID =model.SelectedManufactureID ;
//set other relevant properties also
db.Items.Add(ıtem);
db.SaveChanges();
return RedirectToAction("Index");
}
// reload the dropdown before returning to the view
model.Manufacturers=GetManufacturerList();
return View(model);
}
Try to make the relationship more explicit, making properties virtual and adding an attribute:
public class Item
{
...
[ForeignKey("Manufacturer")]
public int? ManufacturerID { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
public class Manufacturer
{
...
public virtual List<Item> Items { get; set; }
}
Edit:
And you can use a more tied way of building the drop down:
#Html.DropDownListfor(x=>x.SelectedManufactureID ,
ViewBag.ManufacturerID as SelectList,"Choose one")
Edit 2:
A better approach is to make a specific model for the view (called ViewModel) to represent data and build the view like #Shyju said.
Found the problem. The Viewbag I was sending to the view should be named as ManufacturerID, I was sending Manufacturers and somehow it was not matching although it populated the dropdown.
I have MVC3 website with edit form. On this form there is DropDownList that shows list of values that can be chosen. I want it to be set at previously selected value(on create form). This value is in Model.Status. I thought that this code would work:
#Html.DropDownList("Status",
new SelectList(ViewBag.Status as System.Collections.IEnumerable, "Id", "Status", Model.Status))
But the DropDownList is always set on first value from the list. I have checked - the correct value is in Model.Status.
Value of Model.Status is an id of status from list. ViewBag.Status is a list with id and string description - Status.
How to make it show the right value?
Any help much appreciated!
Have you checked this bug
Avoid to use same name of DropDownListand SelectList.
#Html.DropDownListFor(x=>x.SelectedItemId,
new SelectList(ViewBag.Status as System.Collections.IEnumerable,"Id",
"Status"),"Select Item")
But If i am writing this code, i would get rid of the ViewBag and change that to use another strongly typed object
public class YourMainViewModel
{
public int ID { set;get;}
public int SelectedItemId { set;get;}
public IEnumerable<Item> Items();
//other properties
}
public class Item
{
public int Id { set;get;}
public string Status { set;get;}
}
Instead of sending the collection in Viewbag, i would use my new model properties now
public ActionResult EditUser(int id)
{
var user=myRepositary.GetUser(id);
user.Items=myRepositary.GetAllItems();
user.SelectedItemId=5; // replace with the value from your database here,
}
Now in my View which is strongly typed to YourMainViewModel, I will write this
#Html.DropDownListFor(x=>x.SelectedItemId,
new SelectList(Model.Items,"Id",
"Status"),"Select Item")
Here is some sample code that you can modify and use in your scenario. I have an Edit view, on this view are a list of banks in a dropdown, and the bank that is associated with this application is already pre-selected in the list.
My view:
#model MyProject.ViewModels.MyViewModel
My banks dropdown:
<td><b>Bank:</b></td>
<td>
#Html.DropDownListFor(
x => x.BankId,
new SelectList(Model.Banks, "Id", "Name", Model.BankId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.BankId)
</td>
My MyViewModel:
public class MyViewModel
{
// Partial class
public int BankId { get; set; }
public IEnumerable<Bank> Banks { get; set; }
}
My Edit action method:
public ActionResult Edit(int id)
{
// Get the required application
GrantApplication application = grantApplicationService.FindById(id);
// Mapping
MyViewModel viewModel = (MyViewModel)
grantApplicationMapper.Map(
application,
typeof(GrantApplication),
typeof(MyViewModel)
);
// BankId comes from my table. This is the unique identifier for the bank that was selected when the application was added
// Get all the banks
viewModel.Banks = bankService.FindAll().Where(x => x.IsActive);
return View(viewModel);
}
My bank class:
public class Bank
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
Doing it this way will have a selected value in your dropdown after the form has loaded.
I hope this helps :)