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.
Related
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.
What I have is a form with multiple inputs that I want to use to query database for some results. Form has some default values and it all works, however I have problem submitting it to itself.
The returned error is "No paramaterless constructor defined for this object" and it is caused by SelectList object.
I have tried this solution and made psUserType private with getter and setter and intialized it as empty list, but then my dropDown menu had no values on start. Not sure why GetUserTypes hadn't filled them.
What am I doing wrong here? How does one have both preselected values and also send the same model with user-selected values, while also displaying results on the same page?
Does it make sense to use the same model for all 3 actions: 1. display form and inputs with default values 2. post selected values during submit 3. return results and selected values? I've read this solution also but not sure how to use 2 or 3 separate models here.
Any help is appreciated. Thanks in advance.
Model
public class SearchDownloadsModel
{
public SelectList psUserType { get; private set; } //causes problem on submit
public string psText { get; set; }
public MultiSelectList psColumns { get; private set; }
public IEnumerable<ResultsRowModel> psResults { get; set; }
public SearchDownloadsModel()
{
this.psUserType = GetUserTypes();
this.psColumns = GetColumns();
this.psResults = new List<ResultsRowModel>(); //empty by default
}
public SelectList GetUserTypes()
{
List<SelectListItem> items = new List<SelectListItem>()
{
new SelectListItem { Value="user", Text="Single User" },
new SelectListItem { Value="group", Text="User group" },
...
};
return new SelectList(items, "Value", "Text");
}
public MultiSelectList GetColumns()
{
List<SelectListItem> items = new List<SelectListItem>()
{
new SelectListItem { Value = "user", Text="Username" },
new SelectListItem { Value = "file", Text="Filename" },
new SelectListItem { Value = "titl", Text="Title" },
new SelectListItem { Value = "auth", Text="Author" },
...
};
return new MultiSelectList(items, "Value", "Text");
}
}
public class ResultsRowModel
{
public int ID { get; set; }
public string EventTime { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
public string UserName { get; set; }
...
}
View
#model Proj.Models.SearchDownloadsModel
#using (Html.BeginForm("Downloads", "Home", FormMethod.Post))
{
#Html.DropDownListFor(x => x.psUserType, Model.psUserType)
#Html.TextBoxFor(x => x.psText)
#Html.ListBoxFor(x => x.psColumnsSelected, Model.psColumns, new { multiple = "multiple" })
<button type="submit" class="btn btn-primary">Search</button>
}
#if (Model.psResults != null && Model.psResults.Any())
{
<table>
<tr>
<th>User</th>
<th>File</th>
</tr>
#foreach (var row in Model.psResults)
{
<tr>
<td>#row.UserName</td>
<td>#row.FileName</td>
</tr>
}
</table>
}
Controller
[HttpGet]
public ActionResult Downloads()
{
SearchDownloadsModel model = new SearchDownloadsModel();
model.psColumnsSelected = new List<string>() { "user", "file" }; //preselected values
return View(model);
}
[HttpPost]
public ActionResult Downloads(SearchDownloadsModel model)
{
model.psResults = queryDatabase(model);
return View(model);
}
private List<ResultsRowModel> queryDatabase(SearchDownloadsModel model)
{
//...
}
EDIT: Added ResultsRowModel under SearchDownloadsModel
In ASP.NET MVC you should only put variables containing the posted or selected values in the ViewModel class. Select List items are considered extra info and are typically passed from the Action Method into the View (.cshtml) using ViewBag items.
Many of the rendering extension methods are even written specifically for such an approach, leading to code such as this:
Controller
ViewBag.PersonID = persons.ToSelectList(); // generate SelectList here
View
#Html.DropDownListFor(model => model.PersonID)
#* The above will look for ViewBag.PersonID, based on the name of the model item *#
The DropDownListFor generates a <select> element with the name of the property you bind it to. When you submit the form, that name will be included as one of the form fields and its value will be the option's value you select.
You're binding the DropDownList to a property of type SelectList (psUserType) and when your action is called, a new instance of SelectList must be created in order to bind the form field to it. First of all, the SelectList class does not have a parameterless constructor and, thus, your error. Secondly, even if a SelectList could be created as part of model binding, the <select> element is submitting a string value which wouldn't be convertible to SelectList anyways.
What you need to do is to add a string property to your SearchDownloadsModel, for example:
public string SelectedUserType { get; set; }
Then bind the dropdownlist to this property:
#Html.DropDownListFor(x => x.SelectedUserType, Model.psUserType)
When you submit the form, this new property will have the value you selected in the drop down.
Peter's answer and Stephen's comments helped me solve the problem.
Pehaps someone will find it useful.
Any further suggestions always welcome.
Model
public class PobraniaSzukajModel
{
public IEnumerable<SelectListItem> UserTypes { get; set; }
public string psSelectedUserType { get; set; }
public IEnumerable<SelectListItem> Columns { get; set; }
public IEnumerable<string> psSelectedColumns { get; set; }
public string psText { get; set; }
public ResultsModel psResults { get; set; }
}
View
#Html.ListBoxFor(x => x.psSelectedUserType, Model.Columns)
#Html.TextBoxFor(x => x.psText)
#Html.ListBoxFor(x => x.psSelectedColumns, Model.Columns)
Controller
[HttpGet]
public ActionResult Downloads()
{
SearchDownloadsModelmodel = new SearchDownloadsModel();
model.UserTypes = GetUserTypes();
model.Columns = GetColumns();
model.psColumnsSelected = new List<string>() { "user", "file" }; //preselected values
return View(model);
}
[HttpPost]
public ActionResult Downloads(SearchDownloadsModel model)
{
model.UserTypes = GetUserTypes();
model.Columns = GetColumns();
model.psResults = GetResults(model);
return View(model);
}
public SelectList GetUserTypes()
{
//...
}
public MultiSelectList GetColumns()
{
//...
}
public ResultsModel GetResults()
{
//...
}
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.
Unable to bind model with value from #Html.DropDownListFor field in MVC3 (razor) of a strongly typed view.
Model used for strongly typed view:
public class MyModel
{
public string Name{get;set;}
pulic int Status_ID{get;set;}
}
In strongly typed view:
#Html.DropDownListFor(m=> m.Status_ID, new SelectList(Repo.AllStatus, "ID", Name"), new {#style = "width: 100%;" })
Before submitting the form I selected the option with ID=24(i.e. value=24 option is selected)
In controller
public ActionResult AddMyModel(MyModel myModel)
{
}
While debugging, in controller, I got that:
myModel.Name is expected value but
myModel.Status_ID is 0 not 24
where am I going wrong??
You need to pass in a view model to your view with all the statuses already populated.
Here is a solution to your problem. Modify it to fit in with your scenario. I hope I haven't left out anything. The code below is what I am assuming your models might look like.
Your status class:
public class Status
{
public int Id { get; set; }
public string Name { get; set; }
}
On your view you need to pass in a view model that contains a list of all your statuses:
public class YourViewModel
{
public int StatusId { get; set; }
public IEnumerable<Status> Statuses { get; set; }
}
Your controller:
public class YourController : Controller
{
private readonly IStatusRepository statusRepository;
public YourController(IStatusRepository statusRepository)
{
this.statusRepository = statusRepository;
}
public ActionResult YourAction()
{
YourViewModel viewModel = new YourViewModel
{
Statuses = statusRepository.FindAll()
};
return View(viewModel);
}
}
And then your view will look something like this:
#model YourProject.ViewModels.Statuses.YourViewModel
#Html.DropDownListFor(
x => x.StatusId,
new SelectList(Model.Statuses, "Id", "Name", Model.StatusId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.StatusId)
I hope this can help you in the right direction and shed some light on what you are trying to achieve.