I'm a brand new user here - but I've been searching for a couple of hours now to solve following problem:
I've got 2 Entities - Category and Item.
Each Item should belong to a Category - therefore I would like to have a DropDownList which shows all existing Categories when Creating a new Item.
So far my code shows the DropDownList with all the Categories, but when I select a Category and Submit the form (POST) the value for Category is always null.
This naturally causes ModelState.IsValid to be false, because Category isn't nullable.
How can I get the User-Selected-Value into my Create(POST) method?
I've got a Controller with following Methods to Create a new Item:
// GET Method
public ActionResult Create()
{
ViewBag.Category = new SelectList(db.CategorySet, "Id", "CategoryName");
return View();
}
[HttpPost]
public ActionResult Create(Item item)
{
if (ModelState.IsValid)
{
db.ItemSet.Add(item);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(item);
}
And this is the DropDownList in my View (Create.cshtml):
<div class="editor-field">
#Html.DropDownList("Category", (IEnumerable<SelectListItem>) ViewBag.Categories, "--Select Category--")
</div>
Finally I ended up with a custom view model - that way I got it working...
For those of you who don't know what a custom view model is:
You create a new class which contains all the values you need to create your new object, in my example a class which contains a SelectList (property) of available Categories, an integer value (property) for SelectedCategoryId and the Item (property) you want to create.
In your cshtml file you add this class as #model ....CustomCreateItemModel and use it in your DropDownList
If your Item has a CategoryId property:
public class Item
{
public int CategoryId {get;set;]
}
You will need to name your DropDownList to "CategoryId" so that the ModelBinder will be able to bind the value correctly
Or use the strongly typed helper:
Html.DropDownListFor(x=>x.CategoryId...)
Thanks Armen.
I had the same issue with my dropdown list being populated OK from the database but the OrganisationID (in my case) not making it to the database when a new record was created (in my case only 0 was always captured) - until I just changed the name of the ViewBag to be identical to the value in the dropdown (i.e. both OrganisationID) - as you had helpfully pointed out - and now it works!
For what it's worth, for anyone else going through the frustration that "Desperate coder" and I went through when our naming wasn't consistent to enable binding, here's what I have used to get a dropdown list working (sorry - NOT using the Entity Framework, but the principle should still be clear and easy to adapt if you are using the EF):
But the key takeaway is identical naming to enable binding. Thanks again Armen!
MODEL
public class Organisation_Names
{
public DataSet GetOrg_Names()
{
SqlConnection cn = new SqlConnection(#"Data Source=XXXXXXXXX;User ID=XXXXXXXXX;Password=XXXXXXXXXXX;Initial Catalog=XXXXXXXXXXXX");
SqlCommand cmd = new SqlCommand("sp_GetOrg_Names", cn);
cn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
return ds;
}
}
CONTROLLER
//
// GET: /Services/Create
**public ActionResult Create(Organisation_Names organisation_names)
{
DataSet ds = organisation_names.GetOrg_Names();
ViewBag.OrganisationID = ds.Tables[0];
List<SelectListItem> items = new List<SelectListItem>();
foreach (System.Data.DataRow dr in ViewBag.OrganisationID.Rows)
{
items.Add(new SelectListItem { Text = #dr["OrganisationName"].ToString(), Value = #dr["OrganisationID"].ToString() });
}
ViewBag.OrganisationID = items;
return View();
}
//
// POST: /Services/Create
[HttpPost]
[ValidateAntiForgeryToken]
**public ActionResult Create(CreateServiceModel createservicemodel, Organisation_Names organisation_names, FormCollection selection)
{
DataSet ds = organisation_names.GetOrg_Names();
if (ds == null)
{
return HttpNotFound();
}
ViewBag.OrganisationID = ds.Tables[0];
List<SelectListItem> items = new List<SelectListItem>();
foreach (System.Data.DataRow dr in ViewBag.OrganisationID.Rows)
{
items.Add(new SelectListItem { Text = #dr["OrganisationName"].ToString(), Value = #dr["OrganisationID"] + 1.ToString() });
}
ViewBag.OrganisationID = items;**
if (this.IsCaptchaVerify("Answer was incorrect. Please try again."))
{
try
{
int _records = createservicemodel.CreateService(createservicemodel.OrganisationID, createservicemodel.ServiceName, createservicemodel.ServiceDescription, createservicemodel.ServiceComments, createservicemodel.ServiceIdentificationNumber, createservicemodel.CreatedBy, createservicemodel.NewServiceID);
if (_records > 0)
{
return RedirectToAction("Index", "Services");
}
}
catch
//else
{
ModelState.AddModelError("", "Cannot Create");
}
}
{
return View(createservicemodel);
}
}
VIEW
#model WS_TKC_MVC4.Models.CreateServiceModel
#using CaptchaMvc.HtmlHelpers
#using WS_TKC_MVC4.Models
#{ViewBag.Title = "Service added by " ;} #User.Identity.Name
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"> </script>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>CreateServiceModel</legend>
<div class="editor-label">
<p>Select Organisation</p>
</div>
<div class="editor-field">
#Html.DropDownList("OrganisationID")
#Html.ValidationMessageFor(model => model.OrganisationID)
#Html.EditorFor(model => model.OrganisationID)
</div>
(Some more fields)
<div class="editor-label">
#Html.LabelFor(model => model.MathCaptcha)
</div>
#Html.MathCaptcha("Refresh", "Type answer below", "Answer is a required field.")
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Related
View Markup :
#Html.DropDownListFor(model => model.entityType, ViewBag.entityType as SelectList, "Select Type", new { #class = "custom-select"})
This is the dropdown list in .NET and "select Type" is the option label.
My expectation : I want to disable "Select Type" option label. how can I do this ?
Thanks in advance who's help me.
Regards:
PHioNiX
My expectation : I want to disable "Select Type" option label. how can
I do this ?
Well,it can be implemented using couple of ways. However, the most easiest and efficient way is, we would check SelectList by its class name in your scenario it would be #class = "custom-select" and set the property as we expect here, disable to be more specific. Just like below:
$('.custom-select option:contains("Select Type")').attr("disabled", "disabled");
Note: Here, .custom-select is your class name, we are checking for Select Type and finally setting the attribute disabled. We are done. Why its efficient, because looping always cost a lot. We are not using loop here which always has Big 0 impact.
Complete Solution:
Model:
public class EntityTypeModel
{
public string? entityType { get; set; }
}
Controller:
public IActionResult Create()
{
List<SelectListItem> entityTypeList = new List<SelectListItem>();
entityTypeList.Add(new SelectListItem { Text = "Entity-Type-C#", Value = "Entity-Type-C#" });
entityTypeList.Add(new SelectListItem { Text = "Entity-Type-SQL", Value = "Entity-Type-SQL" });
entityTypeList.Add(new SelectListItem { Text = "Entity-Type-Asp.net core", Value = "Entity-Type-Asp.net core" });
ViewBag.entityType = entityTypeList;
return View();
}
View:
#model DotNet6MVCWebApp.Models.EntityTypeModel
#{
ViewData["Title"] = "Create";
}
<h4>Entity Type Dropdown</h4>
<hr />
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label asp-for="entityType" class="control-label"></label>
#Html.DropDownListFor(model => model.entityType, #ViewBag.entityType as SelectList, "Select Type", new { #class = "custom-select"})
<span asp-validation-for="entityType" class="text-danger"></span>
</div>
</div>
</div>
#section scripts {
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script>
$(document).ready(function () {
$('.custom-select option:contains("Select Type")').attr("disabled", "disabled");
});
</script>
}
Output:
Update:
Another thing you can do is: You can set your "Select Type" text from the backend like this way:
entityTypeList.Add(new SelectListItem { Text = "Select Type", Value = "Select Type" });
and then you can check if the the user has selected Select Type in that case you can update ModelState with the error message as below:
if (EntityTypeModel.entityType.Contains("Select Type"))
{
ModelState.AddModelError("", "Entity Type should not be Select Type");
}
I'm having trouble getting the data from a DropDownListFor using a ViewBag list with my model. Here is my Controller code:
[HttpGet]
public ActionResult JoinTeam()
{
var TeamList = _db.TeamModels.ToList();
SelectList list = new SelectList(TeamList, "Id", "TeamName");
ViewBag.TeamList = list;
return View();
}
And the Razor view form looks like this:
#using (Html.BeginForm("JoinTeam", "Home", FormMethod.Post))
{
#Html.TextBoxFor(m => m.DisplayName, new { #class = "form-control form-control-lg", placeholder = "Enter your Battle Net ID" })
<br/>
#Html.DropDownListFor(m => m.TeamModel, (SelectList)ViewBag.TeamList, "- Select a Team to Join -", new { #class= "form-control form-control-lg" })
<br />
<button type="submit" class="btn btn-primary" style="width:100%;text-align:center;">Submit</button>
}
The TextBoxFor helper is returning the data correctly, but whatever option I have selected in the drop down does not get passed into my post method. Does anyone have any ideas?
The post action does work as it's getting the data from the model for the TextBoxFor help, but here's what it looks like:
[HttpPost]
public async Task<ActionResult> JoinTeam(GuardianModel model)
{
try
{
string BNETId = model.DisplayName.Replace("#", "%23");
long memberId = 0;
if (ModelState.IsValid)
{
Bungie.Responses.SearchPlayersResponse member = await service.SearchPlayers(MembershipType.Blizzard, BNETId);
memberId = member[0].MembershipId;
}
using (var context = new CoCodbEntities1())
{
var g = new GuardianModel
{
MembershipId = memberId.ToString(),
DisplayName = BNETId,
MembershipType = 4,
TeamID = model.TeamModel.Id
};
TempData["UserMessage"] = ViewBag.TeamList.Id;
return RedirectToAction("Success");
}
}
catch
{
}
return View();
}
These are the values getting passed into the Post action
From the screenshot you shared, it looks like TeamModel property is the virtual navigational property of type TeamModel. You should not bother about loading that. All you need to worry about loading the forign key property value (usually a simple type like an int or so.
Your SELECT element name should be TeamID. When the form is submitted, it will map the selected option value to the TeamID property value of your model which is the foreign key property.
#Html.DropDownListFor(m => m.TeamID, (SelectList)ViewBag.TeamList,
"- Select a Team to Join -", new { #class= "form-control form-control-lg" })
While this might fix the issue, It is a good idea to use a view model instead of using your entity class.
I found the issues I was having. All I needed to get passed into the post action was the Id of the TeamModel. So I changed this line:
#Html.DropDownListFor(m => m.TeamModel.Id, (SelectList)ViewBag.TeamList, "- Select a Team to Join -", new { #class= "form-control form-control-lg" })
I just added the Id and it seemed to work.
I'm doing a management application users have a part where I have a form with a <select></select>
Which is filled from a
#{ Html.RenderAction ("ListaTipoDeUsuarios", new {selected = 0}); }
This (Index.cshtml):
...
<div class="lg-xs-12">
<label>Tipo Usuario</label>
<select name="tipoUsuario" class="form-control" >
#{Html.RenderAction("ListaTipoDeUsuarios", new { selected = 0 });}
</select>
</div>
....
I have my function in the controller which performs the query to bring the list of types of users (HomeController.cs)
[ChildActionOnly]
public PartialViewResult ListaTipoDeUsuarios()
{
string dtTipoUser = client.GetTiposUsuario("{}");
DataTable dt = (DataTable)JsonConvert.DeserializeObject(dtTipoUser, typeof(DataTable));
List<TipoUsuarioBO> listaTiposUsuarios = new List<TipoUsuarioBO>();
foreach (DataRow row in dt.Rows)
{
TipoUsuarioBO tipoUsuario = new TipoUsuarioBO();
tipoUsuario = TiposUsuarioBR.MapeoTipoUsuario(row, tipoUsuario);
listaTiposUsuarios.Add(tipoUsuario);
}
return PartialView(listaTiposUsuarios);
}
And my view with the list (ListaTipoDeUsuarios.cshtml)
#foreach (var item in Model)
{
<option value="#item.Id">#item.Id - #item.Descripcion</option>
}
My question is, how to make when loading the list brings one of the selected item.Currently when charging the view brings selected by default the first item in the list.
NOTE: Try changing the "0" of the "new selected = {0}" but does nothing.
You will need to change the Model of the PartialView which is rendering the options. You have 2 options.
Change the existing TipoUsuarioBO object to add another property named SelectedID,
OR
Create a new Model with the following declaration.
public class OptionsModel <-- Rename to naming conventions
{
public List<TipoUsuarioBO> TipoUsuarioBO { get; set; }
public int SelectedID {get; set; }
}
And, while rendering option elements, use the following
#foreach (var item in Model.TipoUsuarioBO)
{
<option value="#item.Id" #Html.Raw(#item.Id == Model.SelectedID ? "selected" : "") >#item.Id - #item.Descripcion</option>
}
Why you don't try using List<SelectListItem> as the model of ListaTipoDeUsuarios.cshtml view.
[ChildActionOnly]
public PartialViewResult ListaTipoDeUsuarios()
{
string dtTipoUser = client.GetTiposUsuario("{}");
DataTable dt = (DataTable)JsonConvert.DeserializeObject(dtTipoUser, typeof(DataTable));
List<SelectListItem> listaTiposUsuarios = new List<SelectListItem>();
foreach (DataRow row in dt.Rows)
{
TipoUsuarioBO tipoUsuario = new TipoUsuarioBO();
tipoUsuario = TiposUsuarioBR.MapeoTipoUsuario(row, tipoUsuario);
listaTiposUsuarios.Add(new SelectListItem()
{
Text = tipoUsuario.Id+"-"+tipoUsuario.Descripcion,
Value = tipoUsuario.Id.ToString(),
Selected = true //if you want this item selected otherwise false
});
}
return PartialView(listaTiposUsuarios);
}
and your view
#Html.DropDownList("The name of the field", Model, new { #class = "any-class"})
I have come across a problem. I am currently attempting to make a users page in which some of the dropdowns are variable and determined by their 'access level'. I then want to save the data from the view into a list and then handle it in the 'Post' controller method. I found this link about a possible solution (Assign selectlist to dynamically created dropdown in MVC) but I am still running into problems.
Here is my controller code I am using to set up the data that needs to generate the dropdowns:
var permData = db.LabPermissions.Where(x => x.AccessLevel == 1).ToList();
//sets up generic dropdown data used for all dropdowns
ViewBag.DropDownData = new List<SelectListItem>
{
new SelectListItem{ Value = "0",Text = "No"},
new SelectListItem{ Value = "1",Text = "Yes"},
};
ViewModel obj = new ViewModel();
obj.DataFromController = permData;
//other viewmodel data
return("MyView",obj);
I then pass the data to my view which looks like this (this is also how the stack overflow link set up the view)
#for(int i = 0; i < Model.DataFromController.Count(); i++)
{
<div class="row">
<div class="col-md-2">
<b>#Html.DisplayFor(m => m.DataFromController[i].Lab.LabName)</b>
</div>
<div class="col-md-2">
#Html.DropDownListFor(m => m.DataFromController[i].Assigner, (SelectList)ViewBag.DropDownData, "Select One")
</div>
<div class="col-md-8">
</div>
</div>
}
After I get this set up, and run the application, this is the error I receive:
Additional information: Cannot convert type 'System.Collections.Generic.List<System.Web.Mvc.SelectListItem>' to 'System.Web.Mvc.SelectList'
And the error is placed on my #Html.DropDownListFor line of code in my view.
Thank you for any help!
Try creating a new selectlist instead and put your selectlistitems in it.
#Html.DropDownListFor(m => m.DataFromController[i].Assigner,
new SelectList(ViewBag.DropDownData, "Value", "Text", "Select One")
Or, since you got a ViewModel you can add a public property that can hold your selectlistitems.
public class ViewModel
{
public IEnumerable<SelectListItem> DropDownData { get; set; }
}
Controller:
var permData = db.LabPermissions.Where(x => x.AccessLevel == 1).ToList();
var vm = new ViewModel();
var list = new List<SelectListItem>
{
new SelectListItem{ Value = "-1", Text = "Select One", Selected = true},
new SelectListItem{ Value = "0",Text = "No"},
new SelectListItem{ Value = "1",Text = "Yes"}
};
vm.DropDownData = list;
vm.DataFromController = permData;
return View(vm);
View:
#model YourNameSpace.Models.ViewModel
#for(int i = 0; i < Model.DataFromController.Count(); i++){
#Html.DropDownListFor(m => m.DataFromController[i].Assigner, Model.DropDownData)
}
I believe that you're trying to cast SelectListItem to SelectList and that is the reason why you're getting that error. I've done the same feature as a part of my project and I'm taking the values for the dropdownlist from the database.
and for displaying, here is my code(modified a bit based on your model variables
My Controller method
public ActionResult GetDropDownList()
{
List<SelectListItem> dropDownList= new List<SelectListItem>();
using (var context = new assessmentEntities())
{
//getting data from the DB
var result = context.getDataFromDB().toList();
foreach (var item in result)
{
dropDownList.Add(new SelectListItem() { Text = item.Variable1, Value = item.Variable2});
}
ViewBag.DropDownData = dropDownList;
}
return View();
}`
Here is my View
#Html.DropDownListFor(m => m.DataFromController[i].Assigner,, new SelectList(ViewBag.DropDownData, "Value", "Text")
Hope so this works for you
I have had this error for over a day now and I really can't seem to fix it. I know there are a lot of questions on this topic online which I have read over and over and still haven't solved the issue.
I'm just learning MVC 4 so I'm extremely confused.
I get the error message:
The ViewData item that has the key 'cabinCrewId' is of type 'System.Int32' but must be of type 'IEnumerable'.
Any help or direction would be greatly appreciated!
My Controller:
public ActionResult AddCrew()
{
FlightCabinCrew fcc = new FlightCabinCrew();
return View(fcc);
}
Post action:
[HttpPost]
public ActionResult AddCrew(FlightCabinCrew fcc)
{
if (ModelState.IsValid)
{
using (A1Context db = new A1Context())
{
var data = from person in db.person
from flightcrew in db.flightcabincrew
from cabincrew in db.cabincrew
where flightcrew.cabinCrewId == cabincrew.person
where cabincrew.person == person.id
select person.name;
ViewBag.list = new SelectList(data.ToList(), "id", "name");
db.flightcabincrew.Add(fcc);
db.SaveChanges();
return RedirectToAction("Index");
}
}
else
{
using (A1Context db = new A1Context())
{
var data = from person in db.person
from flightcrew in db.flightcabincrew
from cabincrew in db.cabincrew
where flightcrew.cabinCrewId == cabincrew.person
where cabincrew.person == person.id
select person.name;
ViewBag.list = new SelectList(data.ToList(), "name", "name");
return View(fcc);
}
}
}
}
And my view:
<div class="editor-label">
#Html.LabelFor(model => model.cabinCrewId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.cabinCrewId, (SelectList)ViewBag.list)
#Html.ValidationMessageFor(model => model.cabinCrewId)
</div>
Thanks
You need to assign the SelectList to ViewBag in the GET AddCrew method (as you have done in the POST method). Note also you do not need to assign the SelectList in the POST method if ModelState is valid (your saving and then redirecting so its not necessary since your not returning the view)