EditUserViewModel needs a DropDownListFor() - asp.net-mvc

Right now I have added a Region to the ApplicationUser model in Identity 2.0
On the UsersAdmin view, Edit action, I have the following stock code to display/edit the Region of the User:
<div class="form-group">
#Html.LabelFor(model => model.Region, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Region, new { #class = "form-control" })
</div>
</div>
How do I make that TextBox into a DropDownList that allows the user to choose from a list of Region names where Regions is part of ApplicationDbContext?
public class Region
{
[Key]
public Guid ID { get; set; }
public string Name { get; set; }
public Company Company { get; set; }
public Region()
{
this.ID = Guid.NewGuid();
}
}

You could use a view model. In order to render a dropdown you need 2 properties in your view model: a scalar property to hold the selected value and a collection property to represent the list of possible values to be displayed:
public class MyViewModel
{
public Guid SelectedRegionID { get; set; }
public IEnumerable<SelectListItem> Regions { get; set; }
}
That your controller action will populate and pass to the view:
public ActionResult Index()
{
var viewModel = new MyViewModel();
viewModel.Regions = db.Regions.ToList().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name,
});
return View(viewModel);
}
and in the corresponding strongly typed view you could use the DropDownListFor helper:
#model MyViewModel
<div class="form-group">
#Html.LabelFor(model => model.Region, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.SelectedRegionID, Model.Regions, new { #class = "form-control" })
</div>
</div>

Related

how i can send multivalue to create action

i have a doctor i want add doctor subspecialty to the doctor from sub specialties table many to many relationship
i need to add subspecialties from multiselect list but my controller only add first selection , i want my create controller take all passed subspecialties and create it
my model
public partial class DoctorSubSpecialty
{
public int Id { get; set; }
public Nullable<int> DoctorId { get; set; }
public Nullable<int> SubSpecialtyId { get; set; }
public virtual DoctorProfile DoctorProfile { get; set; }
public virtual SubSpecialty SubSpecialty { get; set; }
}
}
create get action
public ActionResult Create()
{
ViewBag.DoctorId = new SelectList(db.DoctorProfiles, "Id", "FullName");
ViewBag.SubSpecialtyId = new MultiSelectList(db.SubSpecialties, "id", "Name");
return View();
}
create post action
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "Id,DoctorId,SubSpecialtyId")] DoctorSubSpecialty doctorSubSpecialty)
{
DoctorSubSpecialty doctorSub = db.DoctorSubSpecialties.Where(d => d.DoctorId == doctorSubSpecialty.DoctorId & d.SubSpecialtyId == doctorSubSpecialty.SubSpecialtyId).FirstOrDefault();
if (doctorSub == null) {
db.DoctorSubSpecialties.Add(doctorSubSpecialty);
await db.SaveChangesAsync();
}
my view
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>DoctorSubSpecialty</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.DoctorId, "DoctorId", htmlAttributes: new { #class = "control-label col-md-2", #id = "DoctorID" })
<div class="col-md-10">
#Html.DropDownList("DoctorId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.DoctorId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SubSpecialtyId, "SubSpecialtyId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("SubSpecialtyId",(MultiSelectList)ViewBag.SubSpecialtyId, htmlAttributes: new { #multiple = "multiple", #class = "form-control" })
#Html.ValidationMessageFor(model => model.SubSpecialtyId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Create a ViewModel specific to your usecase that can actually transport more than one Id.
I.e. you will need an int[] to bind the selection to.
A ViewModel also helps you to get rid of all this ViewBag and [Bind] nonsense.
public class CreateDoctorSubSpecialtyViewModel {
// These are the selected values to be posted back
public int DoctorId { get; set; }
public int[] SubSpecialtyIds { get; set; }
// These are the possible values for the dropdowns
public IEnumerable<SelectListItem> DoctorProfiles { get; set; }
public IEnumerable<SelectListItem> SubSpecialties { get; set; }
}
GET action - initialize the ViewModel and pass it to the View:
[HttpGet]
public ActionResult Create() {
var doctorProfiles = db.DoctorProfiles.Select(d =>
new SelectListItem {
Text = d.FullName,
Value = d.Id
}
).ToArray();
var subSpecialties = db.SubSpecialties.Select(s =>
new SelectListItem {
Text = s.Name,
Value = s.id
}
).ToArray();
var viewModel = new CreateDoctorSubSpecialtyViewModel {
DoctorProfiles = doctorProfiles,
SubSpecialties = subSpecialties
};
return View("Create", viewModel);
}
View "Create.cshtml" (styling removed for clarity) - tell MVC which ViewModel we want to use with #model:
#model CreateDoctorSubSpecialtyViewModel
#using (Html.BeginForm("Create", "YourControllerName", FormMethod.Post)) {
#Html.DropDownListFor(m => m.DoctorId, Model.DoctorProfiles)
#Html.DropDownListFor(m => m.SubSpecialtyIds, Model.SubSpecialties, new { multiple = "multiple" })
<input type="submit" />
}
POST action - use Linq Contains to test against multiple submitted SubSpecialtyIds:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(CreateDoctorSubSpecialtyViewModel postData) {
DoctorSubSpecialty[] allSelectedSubSpecialities = db.DoctorSubSpecialties
.Where(d => d.DoctorId == postData.DoctorId
&& postData.SubSpecialtyIds.Contains(d.SubSpecialtyId))
.ToArray();
// ...
}
EDIT #Html.DropDownListFor requires an IEnumerable<SelectListItem> as second parameter.

Edit page with a foreign key constraint fails in Asp.net MVC

Trying to get familiar with EF model, but I am having trouble at this point - foreign key problem.
So I have two models.
public class Employee
{
[Key]
public int EmpId { get; set; }
public string Name { get; set; }
public int WorkingDateTimeId { get; set; }
public virtual WorkingDateTime WorkingDateTimes { get; set; }
}
public class WorkingDateTime
{
[Key]
public int WorkingDateTimeId { get; set; }
public string Day { get; set; }
}
Creating Employee information works fine. So in my create view, I enter Employee Name, and WorkingDateTime information, which surprised me it automatically creates a row in WorkingDateTime table.
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.WorkingDateTimes.Day, "Day: ", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.WorkingDateTimes.Day, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
However, when I try to edit the specific Employee row, I get this error:
Cannot add or update a child row: a foreign key constraint fails ("test"."employees", CONSTRAINT "FK_Employees_WorkingDateTimes_WorkingDateTimeId" FOREIGN KEY ("WorkingDateTimeId") REFERENCES "workingdatetimes" ("WorkingDateTimeId") ON DELETE CASCADE O)
I am binding these properties in my controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "EmpId,Name,WorkingDateTimes")] Employee employee)
What do I need in order to Edit successfully?

How to save dropdownlist selected value to the database int asp.net MVC 5

I am currently new to Asp.net MVC .In one of the view I add a dropdownlist and I bind this dropdownlist with my database like this
Controller CollegeController
[HttpGet]
public ActionResult Create()
{
IEnumerable<SelectListItem> items = db.College_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Name });
IEnumerable<SelectListItem> item = db.Stream_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Stream });
ViewBag.CollName=items;
ViewBag.StreamName = item;
return View();
}
[HttpPost]
public ActionResult Create(College college)
{
try
{
if(ModelState.IsValid)
{
db.Colleges.Add(college);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CollName = db.Colleges;
return View(college);
}
catch
{
return View();
}
}
This is my model
public class College
{
[Required]
public int Id { get; set; }
[Required]
[Display(Name="College Name")]
public int CollegeName { get; set; }
[Required]
public int Stream { get; set; }
[Required]
[Column(TypeName="varchar")]
public string Name { get; set; }
....
public virtual College_Name College_Name { get; set; }
public virtual Stream_Name Stream_Name { get; set; }
}
This is My View
<div class="form-group">
#Html.LabelFor(model => model.CollegeName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CollName", (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CollegeName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Stream, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("StreamName", (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Stream, "", new { #class = "text-danger" })
</div>
</div>
Now when I check my database after I save the CollegeName and Stream in the database is zero from the dropdownlist.
You have multiple problems with your code. Firstly you dropdownlists are binding to a properties named CollName and StreamName which do not even exist in your model.
Next you cannot name the property your binding to the same as the ViewBag property.
Your view code would need to be (and always use the strongly typed xxxFor() HtmHelper methods
#Html.DropDownListFor(m => m.CollegeName, (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
....
#Html.DropDownListFor(m => m.Stream, (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" }
and in your POST method, the values of college.CollegeName and college.Stream will contain the ID's of the selected options.
You also need to repopulate the ViewBag properties when you return the view in the POST method (as you did in the GET method) or an exception will be thrown (and note that your current use of ViewBag.CollName = db.Colleges; will also throw an exception)
I also strongly suggest you start learning to use view models (views for editing should not use data models - refer What is ViewModel in MVC?) - and use naming conventions that reflect what your properties are, for example CollegeNameList, or CollegeNames, not CollName

MVC5 problems with DropDownList and view model

So I have a simple database table in the form of ID, EmployeeID, date etc. Which creates a normal model:
public partial class WorkItem
{
public int ID { get; set; }
public int EmployeeID { get; set; }
public int LocationID { get; set; }
[DataType( DataType.Date )]
[Display( Name = "Start date" )]
public System.DateTime StartDate { get; set; }
My problem occurs when I need to augment the functionality of this model and so I create a view model to group work items on a weekly basis.
public class WeeklyWorkItemsViewModel
{
public WorkItem WorkItemMonday { get; set; }
public WorkItem WorkItemTuesday { get; set; }
All works perfectly well for the DateTime field in my view (which is bound to the view model):
<div class="form-group">
#Html.LabelFor( model => model.WorkItemMonday.StartDate, "Week start date", htmlAttributes: new { #class = "control-label col-md-2" } )
<div class="col-md-10">
#Html.EditorFor( model => model.WorkItemMonday.StartDate, new { htmlAttributes = new { #class = "form-control" } } )
#Html.ValidationMessageFor( model => model.WorkItemMonday.StartDate, "", new { #class = "text-danger" } )
</div>
</div>
The problem occurs trying to bind the dropdownlilst, it gets populated correctly but the changes are not seen in the controller.
<div class="form-group">
#Html.LabelFor( model => model.WorkItemMonday.EmployeeID, "EmployeeID", htmlAttributes: new { #class = "control-label col-md-2" } )
<div class="col-md-10">
#Html.Hidden( "selectedEmployee" )
#Html.DropDownList( "EmployeeID", null, htmlAttributes: new { #class = "form-control" } )
#Html.ValidationMessageFor( model => model.WorkItemMonday.EmployeeID, "", new { #class = "text-danger" } )
</div>
</div>
The StartDate is updated in the controller.
After mucho head scratching, I finally had to get around this using:
#Html.Hidden( "selectedEmployee" )
And updating this in JQuery. I did try using #html.DropDownListFor but no joy so far.
Can anyone see what's wrong before I pull ALL my hair out.
You model does not contain a property named EmployeeID. But it does have ones named WorkItemMonday.EmployeeID and WorkItemTuesday.EmployeeID.
Stop using DropDownList() and use the strongly typed DropDownListFor() method so that you correctly bind to your model properties.
Modify you view model to include a property for the SelectList
public IEnumerable<SelectListItem> EmployeeList { get; set; }
and populate it in the GET method before you pass the model to the view. Then in the view use
#Html.DropDownListFor(m => m.WorkItemMonday.EmployeeID, Model.EmployeeList, new { #class = "form-control" })
....
#Html.DropDownListFor(m => m.WorkItemTuesday.EmployeeID, Model.EmployeeList, new { #class = "form-control" })
which will correct generate the name="WorkItemMonday.EmployeeID" and name="WorkItemTuesday.EmployeeID" attributes so that they will bind to your model when you post.

how to pass a where statement in a viewbag

I am trying to pass a where statement in a viewbag to a view. I am trying to pass the equipment status that equals 'In' but it won't work. It wont display the condition.
ViewBag.EquipmentID = new SelectList(db.Equipments.Where(o => o .EquipmentStatus== "In"), "EquipmentID", "EquipmentType", hire.EquipmentID);
my view to select an equipment is:
<div class="form-group">
#Html.LabelFor(model => model.EquipmentID, "EquipmentID", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("EquipmentID", String.Empty)
#Html.ValidationMessageFor(model => model.EquipmentID)
</div>
</div>
My hire model is:
public class Hire
{
public int HireID { get; set; }
public int EquipmentID { get; set; }
public int PurchaseID { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReturnedDate { get; set; }
public virtual Purchase Purchases { get; set; }
public virtual Equipment Equipments { get; set; }
}
using the viewmodel method it says in the view that "the name 'model' does not exist in the current context"
this is my view:
<div class="form-group">
#Html.LabelFor(model => model.EquipmentID, "EquipmentID", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.EquipmentID, model.SelectList)
#Html.ValidationMessageFor(model => model.EquipmentID)
</div>
</div>
The 'model' in 'model.Equipment' is underlined with the error
this is my controller:
public ActionResult Create(int ID)
{
var hire = new Hire();
Purchase purchase = db.Purchasess.Find(ID);
ViewHire responseModel = new ViewHire()
{
PurchaseID = purchase.PurchaseID,
EquipmentID = hire.EquipmentID,
SelectList = new SelectList(db.Equipments.Where(o => o.EquipmentStatus == "In"), "EquipmentID", "EquipmentType", hire.EquipmentID),
};
ViewBag.PurchaseID = new SelectList(db.Purchasess, "PurchaseID", "PurchaseID");
return View(responseModel );
}
Consider this:
ViewBag.Equipments = new SelectList(db.Equipments.Where(o => o .EquipmentStatus== "In"), "EquipmentID", "EquipmentType");
And in your view write:
#Html.DropDownListFor(model=>model.EquipmentID,(SelectList)ViewBag.Equipments,String.Empty)
I think that the issue is that you are passing your model through the ViewBag and not passing it through to your view using View() in your controller.
Therefore, when you use a Html helper like #Html.DropDownList(model => model.Property) it won't find the values that you're wanting to pass through.
Your view should have a view model defined in there at the top of the file, then your view knows what type of view model to expect, such as:
#model MyViewModel
Your view model should be defined as a class within your project, such as:
public class MyViewModel
{
public int EquipmentId { get; set; }
public SelectList SelectList { get; set; }
}
Then within your controller, assign the values to an instance of your class:
public ActionResult Index(int id)
{
// Code to retrieve hire and db instances...
var responseModel = new MyViewModel()
{
EquipmentId = hire.EquipmentID,
SelectList = new SelectList(db.Equipments.Where(o => o .EquipmentStatus== "In"), "EquipmentID", "EquipmentType", hire.EquipmentID),
};
// Return your view model to the view without using the ViewBag
return View(responseModel);
}
Now that you're passing your model through, your HTML helpers will have access to the values:
#model MyViewModel
#Html.DropDownListFor(model => model.EquipmentId, model.SelectList)

Resources