I have a form that loads some Partial Views dinamically and one of these Partial Views will load multiple dropdownlists in the screen.
I have a ViewModel (principal): used in the main view
public class CupomFiscalDetalhesViewModel
{
//some properties
public IEnumerable<CupomItensViewModel> CupomItens { get; set; }
}
An intermediate ViewModel: the view model of the partial view:
public class CupomItensViewModel
{
public IEnumerable<TabelaPrecoViewModel> TabelasPreco { get; set; }
public TabelaPrecoViewModel TabelaPrecoSelecionada { get; set; }
}
Where TabelaPrecos is holding the values that I want to show in the DropDownList. and TabelaPrecoSelecionada will hold the selected value.
In the Controller, I'm used to put the values of an IEnumerable into a ViewBag, and use this ViewBag to generate the dropdownlist in the HTML, like this:
ViewBag.TabelaPrecoSelecionada = new SelectList
(
detalhesCupomFiscal.CupomItens.FirstOrDefault().TabelasPreco,
"IdTabela",
"NomeTabela"
);
But I have no idea how to generate multiple dropdowns for each option of CupomItensViewModel, without passing the id of the selected value of each dropdownlist to the controller action (by parameter).
In the Html, I use: but would need to change the name to get binding workin somehow.
#Html.DropDownList("TabelaPrecoSelecionada",(IEnumerable<SelectListItem>)ViewBag.TabelaPrecoSelecionada,
new { #class = "form-control dropdown" })
Does anyone has an Idea how to accomplish it?
I haven't test this but I would maybe create the select list inside your CupomItensViewModel
using System.Linq;
public class CupomItensViewModel
{
public IEnumerable<TabelaPrecoViewModel> TabelasPreco { get; set; }
public TabelaPrecoViewModel TabelaPrecoSelecionada { get; set; }
public IEnumerable<SelectListItem> TabelasPrecoSelectList
{
get
{
return TabelasPreco.Select(x => new SelectListItem()
{
Value = x.IdTabela
Text = x.NomeTabela
Selected = TabelaPrecoSelecionada.IdTabela
}
}
}
}
And Inside your view
#foreach(var item in Model.CupomItens)
{
#Html.DropDownList("TabelaPrecoSelecionada", item.TabelasPrecoSelectList, new { #class = "form-control dropdown" })
}
But if these dropdowns aren't going to be next to each other, I would make
public IEnumerable<CupomItensViewModel> CupomItens { get; set; }
List instead and using index to identify them. CupomItens[x]
Just my 2 cent without checking if it works. Hopefully it helps.
Related
This is the model:
public class PolicyDetail
{
public Policy Policy { get; set; }
public IEnumerable<Insured> Insured { get; set; }
public IEnumerable<Risk> Risk { get; set; }
public IEnumerable<Construction> Construction { get; set; }
}
Construction just looks like this:
public class Construction
{
public int ConstructionID { get; set; }
public string ConstructionType { get; set; }
}
And in the DB, there are only 4 rows. It's basically an enum.
And within Risk is this property:
public int ConstructionID { get; set; }
Before sending the model to the view, we fill up each object within PolicyDetail, where Insured and Risk are children of Policy. Construction is loaded up every time with all four of it's rows.
So, in the model, we are listing off all the Risks. And as we display them, we want to show Constructions as a dropdown list, and set the selected value to whatever is the value in Risk.ConstructionID.
It's amazing how much heart burn these simple dropdowns can be in MVC.
#foreach (var item in Model.Risk)
{
... Other items in Risk
<div class="form-group">
#Html.Label("Construction Type", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList(?????????)
</div>
</div>
... Other items in Risk
}
How do I fill up that drop down with all of the items from
Model.Constrution
and set the selected item to what's in
item.ConstrucitonID
?
Thanks!
EDIT:
Here's the working solution:
#Html.DropDownList("ConstructionType", new SelectList(Model.Construction.Distinct().ToList(), "ConstructionID", "ConstructionType", item.ConstructionID))
You need to convert the IEnumerable<Construction> to SelectList and specify the selected value.
Something like the following (note: I did not code this in VS, so syntax or parameters are probably not correct, but you'll get the idea)
#Html.DropDownList("ddlConstructionId", new SelectList(Model.Constrution, "ConstructionID" , "ConstructionType", item.ConstrucitonID))
You'll need to specify the selected value when creating the SelectList. I think this is the best constructor for you:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField,
object selectedValue
)
So, in your case, it would be:
#Html.DropDownList("CompanyName",
new SelectList(Model.Construction.Distinct().ToList(), "ConstructionID", "ConstructionType", item.ConstrucitonID));
I am relying heavily on EditorTemplates in my application, but I've run into a problem which I can not seem to solve, without not moving away from EditorTemplates for drop down lists.
Consider this (View)Model:
public class CreateStudentViewModel
{
public DropDownList StudentTypes { get; set; }
public CreateStudent Command { get; set; }
}
public class DropDownList {
public string SelectedValue { get; set; }
public IList<SelectListItem> Items { get; set; }
}
public class CreateStudent {
public string Name { get; set; }
public int StudentTypeId { get; set; }
}
I use this to provide a way for the frontend user to set the student type, this is done with the following EditorTemplate:
#model DropDownList
<div class="form-group#(Html.ValidationErrorFor(m => m.SelectedValue, " has-error"))">
#Html.LabelFor(m => m)
#Html.DropDownListFor(m => m.SelectedValue, Model.Items)
#Html.ValidationMessageFor(m => m.SelectedValue, null)
</div>
And used within my view:
#Html.EditorFor(m => m.StudentTypes)
Now this EditorTemplate is binding to the StudentTypes.SelectedValue on DropDownList, which is good in some cases - but I need to bind this to my Model.Command.StudentTypeId here.
I know I can move all this code directly to the view and directly bind it, instead of having it inside a EditorTemplate, but I will try my best to avoid this.
Ideally I am thinking of extending the EditorFor to provide a way like:
#Html.EditorFor(m => m.StudentTypes, new { selectedValue = Model.Command.StudentTypeId });
But I can not seem to translate this to something like:
#Html.DropDownList(#ViewBag.selectedValue.ToString(), Model.Items);
As this just places the value (int) as the field name. Any suggestions is welcome! :-)
Your chief problem here is encapsulating your drop down list in a class in order to rely on the C# type editor template convention. Instead, just use your model directly and use UIHint to tell Razor to use a particular template. Here's a simplified version of what I use:
View Model
[UIHint("Choice")]
public int SelectedFoo { get; set; }
public IEnumerable<SelectListItem> FooChoices { get; set; }
Views\Shared\EditorTemplates\Choice.cshtml
#{
var choices = ViewData["choices"] as IEnumerable<SelectListItem> ?? new List<SelectListItem>();
if (typeof(System.Collections.IEnumerable).IsAssignableFrom(ViewData.ModelMetadata.ModelType) && ViewData.ModelMetadata.ModelType != typeof(string))
{
#Html.ListBox("", choices)
}
else
{
#Html.DropDownList("", choices)
}
}
View
#Html.EditorFor(m => m.SelectedFoo, new { choices = Model.FooChoices })
In case it's not obvious, the conditional in the editor template determines if the property is a value or list type, and either uses a drop down list control or listbox control, respectively.
I have here a scenario. I want to make an HTTP POST action in the form so here's how I did it.
public class Item
{
public Item()
{
Storages = new HashSet<Storage>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Storage> Storages { get; set; }
-- remove some lines for brevity --
}
public class Storage
{
public int Id { get; set; }
public string Name { get; set; }
--- remove some lines for brevity --
}
So basically, An Item has many Storage And so I created viewmodel.
public class CreateStockViewModel
{
public string Name { get; set; }
public int StorageId { get; set; }
-- remove some lines for brevity --
}
In my Controller. I have this
[HttpGet]
public ActionResult Create()
{
ViewBag.Storages = _storageService.All
.OrderBy(i => i.Name)
.ToSelectList(s => s.Name, s => s.Id);
return View();
}
In my View:
#model Wsfis.Web.ViewModels.ItemViewModels.CreateStockViewModel
#Html.DropDownList("Storages")
Now my problem is, when I submit the form. And have Quick Watch to the model being passed. It is Null or 0
public ActionResult Create(CreateStockViewModel item)
{
// some code
}
In a nutshell,
When I submit the form all fields are being bind except for the #Html.DropDownList. Where did I missed?
Some additional side note:
They say Views should be strongly typed. Then what should I pass in View then? (A sample code would be great. Thanks)
As for the ToSelectList method I copy this code (I hope it's alright)
Any help would be much appreciated. Thanks.
Your form input has a different name to your property so the default model binder doesn't know how to bind your model.
You could pass in a different name to use to the DropDownList helper, however I prefer to use the strongly typed helpers:
#Html.DropDownListFor(m => m.StorageId, ViewBag.Storages as IEnumerable<SelectListItem>)
Try like this:
ViewBag.StorageId = _storageService.All
.OrderBy(i => i.Name)
.ToSelectList(s => s.Name, s => s.Id);
in view:
#Html.DropDownList("StorageId")
it will now post the drop down list selected value in CreateStockViewModel object's StorageId property.
i am trying to initialize an empty view model with a drop down property in it so when it comes to controller, it doesnt give error about the dropdown. Below is the code how I am trying to get it to work but it skips over the foreach loop because the model is empty at the start:
ExampleViewModel
public class ExampleViewModel
{
public ExampleViewModel()
{
ExampleViewModel = new ExampleViewModel();
}
public SelectList dropdown{ get; set; }
public string dropdownvalue { get; set; }
}
}
Controller code:
List<ExampleViewModel > integration = new List<ExampleViewModel >();
foreach (var item in ExampleViewModel )
{
item.dropdown= ApplicationService.GetDropdownlist(null);
}
In View my drop down is being called as:
#Html.LabelFor(model => model.dropdown, new { #id = "rightlabel" })
<span>
#Html.DropDownListFor(model => model.dropdownvalue, Model.dropdown)
#Html.ValidationMessageFor(model => model.dropdown)
</span>
is there a possible workaround this so dropdown list gets initialised ?
You seem to be Initialising a variable that does not exist and not initialising the properties that you actually care about..
public class ExampleViewModel
{
public ExampleViewModel()
{
this.dropdown = new List<string>();
this.dropdownvalue = string.Empty;
}
public List<string> dropdown{ get; set; }
public string dropdownvalue { get; set; }
}
}
That will stop null reference exceptions. I would also not place a SelectList in a view model... a List would be much better.
You should construct the SelectList in your view using the List from the view model... replace List<> with something more appropriate depending on your requirements.
So, I've created a View that contains two ListBoxes, AvailableServices and SelectedServices:
#Html.ListBoxFor(x => x.AvailableServices, Enumerable.Empty<SelectListItem>(), new { id = "serviceID" })
#Html.ValidationMessageFor(model => model.AvailableServices)
#Html.ListBoxFor(x => x.SelectedServices, Enumerable.Empty<SelectListItem>(), new { id = "selectedserviceID" })
#Html.ValidationMessageFor(model => model.SelectedServices)
For reference, here is my ViewModel:
namespace Services.ViewModels
{
public class SPServiceTypeViewModel
{
public int Id { get; set; }
public int SPCompanyAccountID { get; set; }
[Display(Name = "Service Category")]
public IEnumerable<SelectListItem> ServiceCategory { get; set; }
[Display(Name = "Available Services")]
public IEnumerable<SelectListItem> AvailableServices { get; set; }
[Display(Name = "Your Services")]
public IEnumerable<SelectListItem> SelectedServices { get; set; }
}
}
My Controller populates the AvailableServices ListBox without issue. And I wrote some JavaScript that lets the user move items (including id and label) from the AvailableServices ListBox to the SelectedServices listbox. No problem there either.
Now here's my problem... I've read a variety of posts but I still don't understand how to best pass data from my SelectedServices ListBox back to my controller upon form submission, because I need to capture both the id and label for each selection.
My goal here is to create a new database row in my SPServiceType table for each item in the SelectedServices ListBox, and I'm clueless. Right now my Controller for saving data looks like this:
[HttpPost]
public ActionResult Create(SPServiceTypeViewModel viewModel)
{
foreach (var item in viewModel.SelectedServices)
{
var spServiceType = new SPServiceType
{
SPCompanyAccountId = viewModel.SPCompanyAccountID,
ServiceCategory = ???,
};
db.SPServiceType.Add(spServiceType);
db.SaveChanges();
return RedirectToAction("Create", "SPServiceLocation");
}
Do I need to not use IENumerable in my ViewModel? Do I need to use JavaScript to pass my SelectedServices values to a hidden List<> prior to submission so that my model binding is easier to accomplish?
To reiterate, I want to capture the id and label values of the selections.
Any code examples on how to approach this within the View, or Post action in the Controller, or general approach advice, would be greatly appreciated.
I had a similar question here.
The recommendation at the time was to accept the selected values in the POST and use a repository pattern (caching if necessary) to translate the values to labels as needed.