How to create view for dropdown? - c#

i have problem with view for dropdown menu. Here is my code.
Model:
public class student
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int StudentId { get; set; }
[Display(Name = "Šifra ispitanika:")]
[Range(1, 9999)]
public int StudentNumber { get; set; }
[Display(Name = "Datum rođenja ispitanika:")]
[DataType(DataType.Date)]
public DateTime DateBirth { get; set; }
[Display(Name = "Mjesto rođenja ispitanika:")]
public string PlaceBirth { get; set; }
[Display(Name = "Datum testiranja ispitanika:")]
[DataType(DataType.Date)]
public DateTime TestDate { get; set; }
[Display(Name = "Godina rođenja majke:")]
[Range(1900, 2000)]
public int MumDate { get; set; }
[Display(Name = "Godina rođenja oca:")]
[Range(1900, 2000)]
public int DadDate { get; set; }
[Display(Name = "Dropdown_test:")]
public string MumSport { get; set; }
[NotMapped]
public List<SelectListItem> MumSports { set; get; }
}
Controller:
public async Task<IActionResult> Create([Bind("StudentId,StudentNumber,DateBirth,PlaceBirth,TestDate,MumDate,DadDate,MumSports")] student student)
{
if (ModelState.IsValid)
{
var MumSports = new student
{
MumSports = new List<SelectListItem>
{
new SelectListItem { Text = "nikako", Value = "1" },
new SelectListItem { Text = "rekreativno", Value = "2" },
new SelectListItem { Text = "amaterski", Value = "3" },
new SelectListItem { Text = "profesionalno", Value = "4" }
}
};
_context.Add(student);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(student);
}
View:
<select asp-for="StudentId" asp-items="#(ViewBag.MumSports)">
<option>Please select one</option>
</select>
</div>
Problem is about View, when i run my app, it shows me the dropdown but without data I created in the controller. I think that this is not good way for creating View. Any idea ??

one thing which you need to make sure of when you populate any content on a page with server derived information is that you pass it down correctly.
From your view, i can see that you are looking for a ViewBag.MumSport. So, that means that in the "get" request of your action, you wil need to populate ViewBag.MumSport with the related values.
The controller youve written also looks a bit confusing... we typically expect to have a "get (verb)" controller which you use to set the page up. We usually do things like create the values for the drop down list and populate anything you need for the page. Usually, no saving of data happens here. However, it appears as though you are saving the drop down list to a database?
I believe you might want something like this:
public IActionResult Create()
{
ViewBag.MumSport = new List<SelectListItem>
{
new SelectListItem { Text = "nikako", Value = "1" },
new SelectListItem { Text = "rekreativno", Value = "2" },
new SelectListItem { Text = "amaterski", Value = "3" },
new SelectListItem { Text = "profesionalno", Value = "4" }
}
return View();
}
[HttpPost]
public IActionResult Create(view model goes in here)
{
Business logic goes here
}
This should mean that your drop down list gets populated but it also shows a distinction between the post and get methods. Post is typically where you would create or save inforamtion to a store (database).
Hope this helps
UPDATE
instead of having all the properties as part of the signature for the post method, you can try using the model you have created:
public async Task<IActionResult> Create(student viewModel)
You then need to make sure your input items on the form have names which match up with the viewmodel (student):
<select asp-for="StudentId" asp-items="#(ViewBag.MumSports)">
if you do this, your properties should automatically bind to the viewModel when you hit the controller. Another benefit of doing it this way is that ModelState.IsValid will then look at all the attributes within that class and perform validation against them when you submit the form. This is particularly useful when setting fields as required using the [Required] attribute

Related

Select tag helper from database ASP.NET Core 3.1

Ok, I'm trying to do a proper dropdown in Core 3.1. In this example https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper
Model has a new list with hardcoded values
public string Country { get; set; }
public List<SelectListItem> Countries { get; } = new List<SelectListItem>
{
new SelectListItem { Value = "MX", Text = "Mexico" },
new SelectListItem { Value = "CA", Text = "Canada" },
new SelectListItem { Value = "US", Text = "USA" },
};
I looked for examples where the list is coming from the database but they are very inconsistent. The only way I was able to do the dropdown list is with the ViewBag which is not advised.
I have two models. 1.
public partial class Glossary
{
public int UniqueId { get; set; }
public int Category { get; set; }
public string DisplayText { get; set; }
}
which is my view model
public partial class AdminUser
{
[Key]
public int Id { get; set; }
public string UserName { get; set; }
public string UserLocation { get; set; }
public string UserStatus { get; set; }
//public IEnumerable<Glossary> Glossary { get; set; } //I used this for ViewBag
public List<SelectListItem> UserLocations { get; } = new List<SelectListItem>
{
according to the example my query should go here
};
}
Here is my controller:
public IActionResult Create()
{
// This is the ViewBag that worked with HTML helpers, but I'm trying to use tag-helpers.
/*IEnumerable<SelectListItem> LocationsList = _context.Glossary.Where(x => x.Category == 1).Select(x => new SelectListItem
{
Value = x.UniqueId.ToString(),
Text = x.DisplayText
});
ViewBag.LocationsList = LocationsList;
*/
return View();
}
All examples that found were hardcoded lists and nothing with getting it from the database. What is the proper way to get the data from the Glossary table through the view model with ViewBag? Any pointers are appreciated.
ALSO:
When using this example: Select Tag Helper in ASP.NET Core MVC
When I used
public SelectList Employees { set; get; }
I got error: InvalidOperationException: The entity type 'SelectListGroup' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'.
Both of my tables have PK and adding [Key] to Glossary model didn't fix it.
If you'd like to retrieve data from db and populate a dropdown with retrieved data through a view model (or ViewBag), you can refer to following code snippet.
In AdminUser view model class, include these properties
public string Selected_Glossary { get; set; }
public List<SelectListItem> Glossary_List { get; set; }
In controller
public IActionResult Create(AdminUser model)
{
var adminuser_model = new AdminUser
{
UserName="test"
//for other properties
};
//retrieve data from Glossary table
var items = _context.Glossary.Where(x => x.Category == 1).Select(x => new SelectListItem
{
Value = x.UniqueId.ToString(),
Text = x.DisplayText
}).ToList();
//pass dropdown items through a view model
adminuser_model.Glossary_List = items;
////pass dropdown items through ViewBag
//ViewBag.Glossary_List = items;
return View(adminuser_model);
}
In view page
#model AdminUser
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<form asp-controller="Home" asp-action="Create" method="post">
<select asp-for="Selected_Glossary" asp-items="Model.Glossary_List"></select>
#*populate it through ViewBag*#
#*<select asp-for="Selected_Glossary" asp-items="ViewBag.Glossary_List"></select>*#
<input type="submit" value="Submit" />
</form>
Test Result

Submit model with SelectList in ASP.NET MVC

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()
{
//...
}

Display my Select List Items in ShortDateString format

I'm not sure what I'm doing wrong. I have a model with a SelectList property that will contain multiple dates as its values. I want to display these values without the timestamp added. How can I show these dates in shortdatetime format? I have the following ViewModel:
public class EditWeightsViewModel
{
[DisplayName("Associates")]
public SelectList AssociatesList { get; set; }
[DisplayName("Week")]
public SelectList WeeksOfEntryList { get; set; }
public decimal Weight { get; set; }
}
Here's part of my controller (*Note, weeks is a List of DateTimes):
editWeightsViewModel.WeeksOfEntryList = new SelectList(weeks.Select(item => new SelectListItem
{
Selected = false,
Value = item.ToString(),
Text = item.ToShortDateString()
}));
My dropdownlist is showing System.Web.MVC.SelectListItem instead of the actual dates. What am I doing wrong? Am I wrong to go about it this way? Would it be easier to create an editor template that displays this in ShortDateTime format?
Html.DropDownListFor helper method's second argument is a collection of SelectListItem. So change the type of WeeksOfEntryList property to a list of SelectListItem. I also added another property, SelectedWeek to store the selected option value.
public class EditWeightsViewModel
{
public string SelectedWeek {set;get;}
[DisplayName("Week")]
public List<SelectListItem> WeeksOfEntryList { get; set; }
[DisplayName("Associates")]
public SelectList AssociatesList { get; set; }
public decimal Weight { get; set; }
}
And when you load the WeeksOfEntryList property value of your viewmodel.
public ActionResult Create()
{
var vm = new EditWeightsViewModel();
vm.WeeksOfEntryList = weeks.Select(s=> new SelectListItem
{ Value=s.ToShortDateString(),
Text=s.ToShortDateString()}).ToList();
//If you want to keep one option selected, Set the vm.SelectedWeek property value.
return View(vm);
}
And in your razor view,
#using YourNameSpaceHere.EditWeightsViewModel
#Html.DropDownListFor(s=>s.SelectedWeek, Model.WeeksOfEntryList ,"Select")

Populate DropDown using array

I need to populate a dropdown with some data i get from a SOAP server. The server provides me an array of the companies.
How would i use it to populate the DD ?
Here is my User class:
public class Usuario
{
public string Nome { get; set; }
public string Token { get; set; }
public IEnumerable<SelectListItem> Unidades { get; set; }
}
Here is where i receive the companies and send it to the view, i get it from another Action that is redirecting to this Action:
var usuario = TempData["objUsuario"] as UsuarioSSO;
if (usuario == null) return RedirectToAction("Index", "Login");
if (usuario.UsuarioUnidades == null)
{
ModelState.AddModelError("", "Usuário não possui unidades");
return View();
}
var model = new Models.Usuario
{
Unidades = usuario.UsuarioUnidades.ToList().Select(x => new SelectListItem
{
Value = x.CodigoEmitente.ToString(),
Text = x.NomeFantasia
})
};
return View(model);
Here is how i'm trying to display it:
#Html.DropDownListFor(x => x.Unidades, new SelectList(Model.Unidades))
I have already tried of everything but it won't work, i get some conversion errors and when i can make it work it won't display the content, it will only display the object inside the Text area
System.Web.Mvc.SelectListItem
You need to have one property for the selected item and the list of available items, e.g.:
public class Usuario
{
public string Nome { get; set; }
public string Token { get; set; }
public string Unidade { get; set; }
public IEnumerable<SelectListItem> Unidades { get; set; }
}
and then create the drop-down like:
#Html.DropDownListFor(x => x.Unidade, Model.Unidades)
You can directly supply the Unidades as it is already IEnumerable<SelectListItem>.
P.S.: I guessed the singular of Unidades as I do not speak your langauge, whatever it is. I recommend to ALWAYS use english in source code.
Your model needs a value type property to bind the selected option to. If CodigoEmitenteis typeof int then you model property needs to be
public int SelectedUnidades { get; set; }
and you need to assign the SelectList to another property in your view model or to a ViewBag property
ViewBag.UnidadesList = new SelectList(usuario.UsuarioUnidades, "CodigoEmitente", "NomeFantasia");
Then in the view
#Html.DropDownListFor(x => x.SelectedUnidades, (SelectList)ViewBag.UnidadesList)

Getting Value cannot be null. Parameter name: items, MVC4 selectList error?

i recently had the dropdownlist working and everything was fine but for some reason it is now throwing value cannot be null exception. I have swapped variable names around and things trying to resolve the error but has had no effect. Could you please take a look at my code and point me in the right direction. I am a beginner with MVC4 and have been working on this problem for hours now, so any help would be appreciated. I have only posted relevant code thanks in advance.
EDIT: it is throwing the error at start of line #Html.DropDownListFor(....) in the view
Model:
public partial class SiteBookingsTable
{
public string departureAirport { get; set; }
public string arrivalAirport { get; set; }
[Required]
[Display(Name = "Flying From")]
public string chooseDepartureAirport { get; set; }
[Required]
[Display(Name = "Flying To")]
public string chooseArrivalAirport { get; set; }
}
View:
#model Project56.Models.SiteBookingsTable
#{
List<Project56.Models.SiteBookingsTable> selectDepFlight = ViewBag.depList;
}
<tr>
<td>#Html.LabelFor(model => model.chooseDepartureAirport)<br />
#Html.DropDownListFor(model => model.chooseDepartureAirport, new SelectList(selectDepFlight,"departureAirport","departureAirport"))</td>
</tr>
Controller:
public ActionResult Create()
{
List<SiteBookingsTable> selectDepFlight = new List<SiteBookingsTable>();
selectDepFlight.Add(new SiteBookingsTable() { listID = 0, departureAirport = "-Select-" });
selectDepFlight.Add(new SiteBookingsTable() { listID = 1, departureAirport = "London (LTN)" });
selectDepFlight.Add(new SiteBookingsTable() { listID = 2, departureAirport = "Manchester (MAN)" });
ViewBag.depList = selectDepFlight;
return View();
}
[HttpPost]
public ActionResult Create(SiteBookingsTable aBooking)
{
if (ModelState.IsValid == true)
{
newBooking.SiteBookingsTables.Add(aBooking);
newBooking.SaveChanges();
return RedirectToAction("Index");
}
return View(aBooking);
}
in your View you are using SelectList(selectDepFlight,
but you are sending a ViewBag variable ViewBag.depList = selectDepFlight;
you want SelectList(ViewBag.depList,
although honestly it should probably be in the Model, not the ViewBag
If I remember correctly the SelectList type must be enumerable. --Source
** Edit, its probably best to return the value as an enumerable from the controller side instead of in the View itself. Also consider utilizing ViewModels and not the Model itself.
List<Project56.Models.SiteBookingsTable> selectDepFlight = ViewBag.depList;
//Add the following line(s) to cast your list to an enumerable.
IEnumerable<Project56.Models.SiteBookingsTable> enumSelectDepFlight = selectDepFlight.AsEnumerable<Project56.Models.SiteBookingsTable>
//Alter the following code
#Html.DropDownListFor(model => model.chooseDepartureAirport, new SelectList(selectDepFlight,"departureAirport","departureAirport"))
//to match the enumerable above
#Html.DropDownListFor(model => model.chooseDepartureAirport, new SelectList(enumSelectDepFlight,"departureAirport","departureAirport"))

Categories