I can display the values from my database both in a dropdownlist and where the value is needed.
But I can't get the value from the dropdownlist to my database while creating something. it's getting null.
I've tried some solutions from s.o.f but they didnt't work.
Models 1:
public class Kategori
{
[Key]
public int KategoriID { get; set; }
public string Namn { get; set; }
}
Models 2:
public class Inlägg
{
[Key]
public int InläggsID { get; set; }
public Kategori Kategori { get; set; }
}
Controller:
// POST: Inlägg/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Titel,Text,Kategori.Namn")] Inlägg inlägg)
//The Kategori is getting null
{
if (ModelState.IsValid)
{
inlägg.Datum = DateTime.Now;
_context.Add(inlägg);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(inlägg);
}
View:
#Html.DropDownList("Kategori", null, htmlAttributes: new { #class = "form-control" })
I've tried using SelectItemList, select with options values, having a SelectItem inside Models class also a "public Kategori List" inside Inlägg.
Don't really know how to solve this. I've just tried 8 hours today, and 2 hours yesterday.
How can I get the value that the user choosen in the dropdownlist instead of getting null? Tell me if I need to send more codes :-)
You should change it;
#Html.DropDownList("Kategori", null, htmlAttributes: new { #class = "form-control" })
to
#Html.DropDownList("SelectedCategory", ViewData["Kategori"] as SelectList, htmlAttributes: new { #class = "form-control" })
The selected dropdown element is passed to serverside as SelectedCategory.
Also, I strongly suggest you to use Model classes instead of ViewData to carry data between controller and view.
You need to add another property for the foreign key value. Since your other related entity class name is Kategori, you may name this new property KategoriId so that it matches the convention for the foreign key property names.
public class Inlagg
{
[Key]
public int InläggsID { get; set; }
public string Titel { get; set; }
public string Text { get; set; }
public DateTime Datum { get; set; }
public virtual Kategori Kategori { get; set; }
public int? KategoriId { set;get;} // This is the new property
}
Now in your form inside your view, make sure the select element rendered by the DropDownList helper has the same name attribute value as the new property name (check the view source of the page)
#Html.DropDownList("KategoriId", ViewData["Kategori"] as SelectList)
Now finally, make sure you include this new input name/property name inside the Bind attributes Include list so that the model binder will bind that.
public async Task<IActionResult> Create([Bind(Include="Titel,Text,KategoriId")]
Inlagg inlagg)
{
// to do : your code for saving and returning something
}
Another option is to use a view model with only needed properties, instead of using the Bind attribute with your entity class
Related
I managed to populate DropDownList with value from a Database in ASP.NET MVC 5. My goal is to assing one of the dropDownList's value to a specific model, and send it back to the Database. So, if i leave the default value in the dropdownlist, the data in SQL server is null, which is Okay, but if I choose an option, I get an error :
Exception thrown: 'System.InvalidOperationException' in System.Web.Mvc.dll ("There is no ViewData item of type 'IEnumerable' that has the key 'Status'."). I tried everything so far and i am opened for suggestions. Thank you !!!
In Controller :
ViewBag.Status = new SelectList(db.Status, "Id", "Name");
in View
#Html.DropDownList("Status","Select status...")
In Controller so far..
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult Apply(ViewModelVM vm,int x=0)
{
myDb db = new myDb();
ViewBag.SocialStatus = new SelectList(db.SocialStatuses, "Id", "StatusDescription");
return View();
}
[HttpPost]
public ActionResult Apply(ViewModelVM vm)
{
if (ModelState.IsValid)
{
using (myDb db = new myDb())
{
var personalinfo = new PersonalInformation()
{
FirstName = vm.PersonalInformation.FirstName,
LastName = vm.PersonalInformation.LastName,
Birthdate = vm.PersonalInformation.Birthdate,
SocialStatus = vm.SocialStatus
};
ViewBag.SocialStatus = new SelectList(db.SocialStatuses, "Id", "StatusDescription");
db.PersonalInformations.Add(personalinfo);
db.SaveChanges();
}
return View("Success");
}
return View();
}
The model:
public partial class Status
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public SocialStatus()
{
PersonalInformations = new HashSet<PersonalInformation>();
}
public int Id { get; set; }
[StringLength(20)]
public string StatusDescription { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<PersonalInformation> PersonalInformations { get; set; }
}
}
The ViewModel:
public class ViewModelVM
{
...
public Status SocialStatus { set; get; }
...
}
Firstly your using a view model so include a property in your view model for the SelectList
public IEnumerable<SelectListItem> StatusList { get; set; }
Next remove the parameter for the model from the GET method (and since you don't appear to be using the value of x, that should be removed also)
[HttpGet]
public ActionResult Apply(ViewModelVM vm,int x=0)
{
myDb db = new myDb();
ViewModelVM model = new ViewModelVM()
{
StatusList = new SelectList(db.SocialStatuses, "Id", "StatusDescription");
};
return View(model); // return the model to the view
}
Next, your dropdown is binding to a property named Status but your view model does not contain a property named status (its SocialStatus) and SocialStatus is a complex object and you cannot bind a <select> to a complex object (a <select> only posts back a single value (or array or values in the case of <select multiple>).
In addition, because your view model contains a property which is a complex object with validation attributes on its properties, ModelState will always be invalid because you do not post back a value for StatusDescription. As a result you always return the view in the POST method, and because you have not reassigned ViewBag.Status = ...., it is null, hence the error.
Remove property public Status SocialStatus { set; get; } and include
[Display(Name = "Social Status")]
[Required(ErrorMessage = "Please select a status")]
public int SocialStatus { get; set; }
an then in the view, strongly bind to your model using
#Html.LabelFor(m => m.SocialStatus)
#Html.DropDownListFor(m => m.SocialStatus, Model.StatusList, "-Please select-")
#Html.ValidationMessageFor(m => m.SocialStatus)
Then, in the POST method, if ModelState is invalid, populate the select list again before returning the view
if(!ModelState.IsValid)
{
model.StatusList = new SelectList(db.SocialStatuses, "Id", "StatusDescription");
return View(model);
}
// save and redirect
Finally, review What is ViewModel in MVC?.
I am using #Html.DropDownListFor for the first time. Code is below.
Model:
class Student
{
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
[Required]
[Display(Name = "Roll Number")]
public string RollNumber { get; set; }
[Required]
[Display(Name = "ClassId")]
public int ClassId { get; set; }
}
class Class
{
[Required]
[Display(Name = "ClassId")]
public string RollNumber { get; set; }
[Required]
[Display(Name = "ClassName")]
public string RollNumber { get; set; }
}
Controller:
public ActionResult Create()
{
Student student = new BusinessEntities.Student();
List<Class> classes = GetAllClasses();
ViewBag.ClassId = new SelectList(classes, "ClassId", "ClassName");
return View(student);
}
[HttpPost]
public ActionResult Create(BusinessEntities.Student student)
{
if (ModelState.IsValid)
{
//Integer has 0 by default. But in our case if it contains 0,
//means no class selected by user
if(student.ClassId==0)
{
ModelState.AddModelError("ClassId", "Select Class to Enroll in");
return View(student);
}
}
}
Student Create View:
<form method="post">
Select Class :
#Html.DropDownListFor(Model=>Model.ClassId,ViewBag.ClassId as IEnumerable<SelectListItem>, "ClassId","ClassName")
#Html.ValidationMessageFor(Model => Model.ClassId)
<input type="submit" value="Submit" />
</form>
Error Message:
The ViewData item that has the key 'ClassId' is of type 'System.Collections.Generic.List`1[[BusinessEntities.Class, BusinessEntities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' but must be of type 'IEnumerable'.
I want ClassId of Student be binded and populated automatically when posted back to Controller. Please help me to get rid of it.
Thanks.
You need to give the SelectList a different name that the property your binding to (say)
ViewBag.ClassList = new SelectList(classes, "ClassId", "ClassName");`
and then
#Html.DropDownListFor(m => m.ClassId, ViewBag.ClassList as IEnumerable<SelectListItem>)
and then ensure if you return the view (for example if ModelState is invalid), that you repopulate the SelectList (as you have done in the GET method). Currently when you return the view, it is null resulting in an error, because if the second parameter is null the fallback is that the helper expects the first parameter to be IEnumerable<SelectListItem> (but its not - its typeof int)
Side notes: Do not use Model => Model.XXX (capital M) and your current use of DropDownistFor() as 2 parameters which make no sense. "ClassId" will add a label option <option value="">ClassId</option> and the last one ,"ClassName" will not do anything.
Edit
In addition, your
if(student.ClassId==0)
{
ModelState.AddModelError("ClassId", "Select Class to Enroll in");
return View(student);
}
is a bit pointless. student.ClassId will never be 0 unless one of the items in your GetAllClasses() has ClassId = 0. You should be using
[Required(ErrorMessage = "Select Class to Enroll in")] // add error message here
public int ClassId { get; set; }
and in the view
#Html.DropDownListFor(m => m.ClassId, ViewBag.ClassList as IEnumerable<SelectListItem>, "--please select--")
which will create the first option with a value of null. If this option were selected, then the DefaultModelBinder will attempt to set the value of ClassId = null which fails (because typeof int cannot be null) and a ModelState error is added and ModelState becomes invalid.
The in the POST method
[HttpPost]
public ActionResult Create(BusinessEntities.Student student)
{
if (!ModelSTate.IsValid)
{
ViewBag.ClassList = // repopulate select list
return View(student);
}
// Save and redirect
}
I have one model called ProductSupplier
I am passing #model IEnumerable to my View
and showing it from view
Now when i submit the form i m not getting list of IEnumerable in my http post method. I want to know the selected supplier from user.
Below is my model
public sealed class ProductSupplier
{
public int CountryId { get; set; }
public int UserId { get; set; }
public bool IsProductSupplier { get; set; }
public string CountryName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
This is my HttpGet method
public ActionResult ManageSupplier(int id)
{
var supplier = App.UsersRepo.GetSupplierForProduct(id);
return View(supplier);
}
And I am binding it via following way (U can suggest me best way I am new bee to MVC)
#model IEnumerable<ProductSupplier>
#using (Html.BeginForm("ManageSupplier", "Products", FormMethod.Post, new { role = "form") })
{ #Html.AntiForgeryToken()
foreach (var item in Model)
{
<div class="checkbox">
<label>
#Html.CheckBoxFor(x => item.IsProductSupplier, new { id = item.Email }) #item.FirstName #item.LastName (#item.Email)
</label>
</div>
}
}
And finally my HttpPost method
[HttpPost]
public ActionResult ManageSupplier(IEnumerable<ProductSupplier> obj)
{ // I m getting obj null in my argument
//I want to Get selected id from obj and want to pass in selectedSupplier
var returnVal = App.ProductRepo.AssigneSupplierForProduct(productId, selectedSupplier);
return Json(new { success = true }, JsonRequestBehavior.DenyGet);
}
can anyone suggest me where i m making mistake.
I am new to MVC any kind of suggestion highly appreciated.
Thank you in advance.
Firstable u cant do it like this.One way to do that is something like this.Here is the basic step how u do that.
1-assign for all checkbox ,checkbox change event with the unique id.
(take a look at here)
2-Cretae a jquery object and store the data when ever the checkbox clicked ,via versa
var ListProductSuppliers ={ {ProductSupplier_info_here },{ProductSupplier_info_here } };
3-later via ajax request,serilize this object(ListProductSuppliers ) and send to your method
4-on server side deserilize this to the IEnumerable<ProductSupplier>
5 later do it whatever u want with those selected suppliars
I am binding my drop down list with database using EF code first approach.My model class is department
public class Department
{
[Key]
public int DepartmentID { get; set; }
[Required]
[Display(Name = "Department")]
public string DepartmentName { get; set; }
}
I am getting all department name in ViewData
ViewData["Departments"] = new SelectList(db.Departments,"DepartmentName");
In my view my code is this
#Html.DropDownList("Departments", "Select Department")
Thid code binding my data but not with name but their are 10 objects like
MyProjectName.Models.Department
MyProjectName.Models.Department
MyProjectName.Models.Department
MyProjectName.Models.Department
MyProjectName.Models.Department
....
Need help what is going wrong in my code.
Try using the correct constructor of the SelectList class taking the collection, the value and text property:
ViewData["Departments"] = new SelectList(db.Departments, "DepartmentID", "DepartmentName");
You might also consider using view models and get rid of the weakly typed ViewData. So, start by defining your view model:
public class MyViewModel
{
public int SelectedDepartmentID { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
}
that your controller action will populate and pass to the view:
public ActionResult Index()
{
var model = new MyViewModel();
model.Departments = db.Departments.ToList().Select(d => new SelectListItem
{
Value = d.DepartmentID.ToString(),
Text = d.DepartmentName,
});
return View(model);
}
and in your strongly typed view you could use the strongly typed DropDownListFor version of the helper to generate the dropdown:
#model MyViewModel
...
#Html.DropDownListFor(x => x.SelectedDepartmentID, Model.Departments, "Select Department")
I need simple DropDownList in form and I don't want to create something like ViewModel.
I have two models(tables) in relation 1:n:
public class Course
{
public int ID { get; set; }
public string Name { get; set; }
}
and
public class Project
{
public int ID { get; set; }
public int CourseId { get; set; }
public int ProjectNo { get; set; }
public string Name { get; set; }
public DateTime Deadline { get; set; }
}
In the 'Create Project' I want to have DropDownList with Id (as value) and Name(as text) from Course table(model). In the new project will be insert chosen CourseId. How can I do that as simple as possible?
Any particular reason why you don't want to use a ViewModel? They're very helpful for this type of problem.
If you don't want to use a ViewModel, then you can construct a specific class in your controller that is an aggregate of the properties you need from both classes:
public ActionResult Show(int id)
{
Course course = repository.GetCourse(id); // whatever your persistence logic is here
Project project = projectRepository.GetProjectByCourseId(id);
string CourseName = from c in course where
c.ID == project.courseID
select c.Name;
IEnumerable<SelectListItem> selectList =
from c in course
select new SelectListItem
{
Selected = (c.ID == project.CourseId),
Text = c.Name,
Value = project.CourseId.ToString()
};
//add the selectList to your model here.
return View(); //add the model to your view and return it.
}
It would be far easier to have a ViewModel for this, so you could have a strongly typed view. Let me show you:
public class ProjectCourseViewModel
{
public SelectList ProjectCourseList {get; private set; }
public Project Project {get; private set; }
public Course Course {get; private set; }
public ProjectCourseViewModel(Project project, Course course)
{
ProjectCourseList = GetProjectCourseSelectList(project, course)
Project = project;
Course = course;
}
private SelectList GetProjectCourseSelectList(Project project, Course course)
{
IEnumerable<SelectListItem> selectList =
from c in course
select new SelectListItem
{
Selected = (c.ID == project.CourseId),
Text = c.Name,
Value = project.CourseId.ToString()
};
}
}
And then your controller would be really simple:
public ActionResult Show(int id)
{
Course course = repository.GetCourse(id);
Project project = projectRepository.GetProjectByCourseId(id);
ProjectCourseViewModel pcvm = new ProjectCourseViewModel(project, course)
return View(pcvm);
}
And then your view takes in a strongly typed model, and you don't have to rely on ViewData, which is a Good Thing.
Note: I haven't compiled this, just written it. There are probably compilation bugs.
probably you could solve it using the following example:
in your controller include a Viewbag
{
Viewbag.Course = db.course.ToList();
var project = new project.....
}
And in your View use the following pattern:
#Html.DropDownList("CourseId",
new SelectList(ViewBag.Course as System.Collections.IEnumerable,
"CourseId", "Name", Model.ID))
where each field represent:
•The name of the form field (CourseId)
•The list of values for the dropdown, passed as a SelectList
•The Data Value field which should be posted back with the form
•The Data Text field which should be displayed in the dropdown list
•The Selected Value which is used to set the dropdown list value when the form is displayed
more info at: http://www.asp.net/mvc/tutorials/mvc-music-store-part-5
brgds.
In the Controler:
var CourseName = from c in course where
c.ID == project.courseID
select c.Name;
SelectList sl = new SelectList(CourseName);
ViewBag.names= sl;
in the view :
#Html.DropDownList("Name", (SelectList)ViewBag.names)