I am new to MVC and trying to understand ViewModels. I understand how to use Create and a ViewModel, But am unsure how to Edit using a View Model?
My VM:
public class BookingViewModel
{
[Display (Name = "Select Patient")]
public Guid PatientId { get; set; }
public IEnumerable<SelectListItem> PatientList { get; set; }
[Display(Name = "Select Practice")]
public Guid PracticeId { get; set; }
public IEnumerable<SelectListItem> PracticeList { get; set; }
[Display(Name = "Select Optician")]
public Guid OpticianId { get; set; }
public IEnumerable<SelectListItem> OpticiansList { get; set; }
public Optician Optician { get; set; }
[Display(Name = "Select Date")]
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime Date { get; set; }
[Display(Name = "Select Time")]
public Guid TimeId { get; set; }
public IEnumerable<SelectListItem> TimeList { get; set; }
}
My Controller:
public ActionResult Create()
{
// Creates a new booking
BookingViewModel bookingViewModel = new BookingViewModel();
// Initilises Select List
ConfigureCreateViewModel(bookingViewModel);
return View(bookingViewModel);
}
// Initilises Select List
public void ConfigureCreateViewModel(BookingViewModel bookingViewModel)
{
// Displays Opticians Name - Needs changed to full name
bookingViewModel.OpticiansList = db.Opticians.Select(o => new SelectListItem()
{
Value = o.OpticianId.ToString(),
Text = o.User.FirstName
});
// Displays Patients name - needs changed to full name DOB
bookingViewModel.PatientList = db.Patients.Select(p => new SelectListItem()
{
Value = p.PatientId.ToString(),
Text = p.User.FirstName
});
// Displays Practice Name
bookingViewModel.PracticeList = db.Practices.Select(p => new SelectListItem()
{
Value = p.PracticeId.ToString(),
Text = p.PracticeName
});
// Displays Appointment Times
bookingViewModel.TimeList = db.Times.Select(t => new SelectListItem()
{
Value = t.TimeId.ToString(),
Text = t.AppointmentTime
});
}
// Allows Admin to create booking for patient
// POST: Bookings1/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(BookingViewModel bookingViewModel)
{
// to ensure date is in the future
if (ModelState.IsValidField("Date") && DateTime.Now > bookingViewModel.Date)
{
ModelState.AddModelError("Date", "Please enter a date in the future");
}
// if model state is not valid
if (!ModelState.IsValid)
{
// Initilises Select lists
ConfigureCreateViewModel(bookingViewModel);
return View(bookingViewModel); // returns user to booking page
}
else // if model state is Valid
{
Booking booking = new Booking();
// Sets isAvail to false
booking.isAvail = false;
booking.PracticeId = bookingViewModel.PracticeId;
booking.Optician = bookingViewModel.Optician;
booking.PatientId = bookingViewModel.PatientId;
booking.Date = bookingViewModel.Date;
booking.TimeId = bookingViewModel.TimeId;
// Generates a new booking Id
booking.BookingId = Guid.NewGuid();
// Adds booking to database
db.Bookings.Add(booking);
// Saves changes to Database
db.SaveChanges();
// Redirects User to Booking Index
return RedirectToAction("Index");
}
}
I am really unsure how to Edit a View Model, any advice would be greatly appreciated
public ActionResult Edit(Guid? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Booking booking = db.Bookings.Find(id);
if (booking == null)
{
return HttpNotFound();
}
BookingViewModel bookingViewModel = new BookingViewModel()
{
Date = booking.Date,
OpticianId = booking.OpticianId,
PatientId = booking.PatientId,
PracticeId = booking.PracticeId,
TimeId = booking.TimeId
};
return View(booking, bookingViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Booking booking)
{
if (ModelState.IsValid)
{
db.Entry(booking).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(booking);
}
There is no overload of Controller.View method that accepts 2 models/objects.
You Edit() GET method needs to be
public ActionResult Edit(Guid? id)
{
....
BookingViewModel bookingViewModel = new BookingViewModel()
{
....
}
// Call the ConfigureCreateViewModel() method so that you SelectList's are populated
// as you have done in the Create() method (ConfigureViewModel might be a better name?)
ConfigureCreateViewModel(bookingViewModel);
return View(bookingViewModel); // adjust this
}
and the POST method needs to be
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(BookingViewModel model)
{
if (!ModelState.IsValid)
{
ConfigureCreateViewModel(model)
return View(model);
}
// Get your data model and update its properties based on the view model
Booking booking = db.Bookings.Find(id);
booking.PracticeId = bookingViewModel.PracticeId;
booking.OpticianId = bookingViewModel.OpticianId;
.... // etc
db.Entry(booking).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
and your view should have #model BookingViewModel
Side note: Your view model should not contain property public Optician Optician { get; set; } (you binding to the property public Guid OpticianId { get; set; })
Related
For example I created a record in assigned asset with asset code (lap001), employee name (hana) and date (08/10/21).
Then I created another record with the same asset code (lap001) different employee name (lana) and date(09/10/21). in other words I have assigned this asset to diffrent employee.
In asset master details of that specific asset code (lap001) screen how to show that this specific asset was assigned to this employee from previous date (08/10/21) to new date (09/10/21).
Now currently Date in AssigningAssetModel is assigned to AssignedToDateNew now how to move the new date to old date when I create a new record and also how to prevent user to put date between previous date (08/10/21) to new date (09/10/21)
AssigningAssetModel class:
public class AssigningAssetModel
{
[key]
public int ID { get; set; }
[Required(ErrorMessage = "Enter Employee Name")]
public string EmployeeName {get; set; }
[Required(ErrorMessage = "Enter AssetCode")]
public string AssetCode { get; set; }
[Required(ErrorMessage = "Enter Date")]
public string Date{ get; set; }
}
AssetMasterModel class:
public class AssetMasterModel
{
[Key]
public int ID { get ;set; }
[Required(ErrorMessage = "Enter AssetCode")]
public string AssetCode { get; set; }
[Required(ErrorMessage = "Enter Employee Name")]
public string EmployeeName{ get; set; }
public string AssignedToDateOld { get; set; }
public string AssignedToDateNew { get; set; }
}
AssigningAsset controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(int id, [Bind("ID,EmployeeName,AssetCode,Date,")] AssigningAssetModel assigningAssetModel)
{
if (id != assigningAssetModel.ID)
return NotFound();
if (!ModelState.IsValid)
return View(assigningAssetModel);
try
{
var masterExist = await _context.Set<AssetMasterModel>()
.FirstOrDefaultAsync( i => i.AssetCode == assigningAssetModel.AssetCode);
if (masterExist == null)
return NotFound();
if (masterExist.EmployeeName != assigningAssetModel.EmployeeName)
{
masterExist.EmployeeName = assigningAssetModel.EmployeeName;
masterExist.AssignedToDateNew = assigningAssetModel.Date;
_context.Entry(masterExist).State=EntityState.Modified;
}
_context.Add(assigningAssetModel);
await _context.SaveChangesAsync();
_context.Update(assigningAssetModel);
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
return RedirectToAction(nameof(Index));
}
AssetMaster controller:
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var assetMasterModel = await _context.AssetMaster
.FirstOrDefaultAsync(m => m.ID == id);
if (assetMasterModel == null)
{
return NotFound();
}
return View(assetMasterModel);
}
So basically in Assigning Asset Index this asset code (laptop0001015) is first assigned to Tom at 22/05/2021 then it has been assigned to Mouffaq at 24/05/2021 now in assetmaster how to show that this asset code in this case (Laptop0001015) was assigned to Tom From 22/05/2021 to 24/05/2021
From what i understand, what you need to do is keep the existing asset date before creating the new record and then assign it to the new record.
prevDate = employee.getCurrentAsset().date
newAsset = new Asset()
newAsset.date = prevDate ;
employee.setCurrentAsset(newAsset) ;
I got a two DropDownList's in View. When i try pass those parameters, method in controller called but parameters equals a null.
When i check in browser (F12-network) i watch parameters - they are sended but in method still nulls
P.S.
I try change type of parameters on List or Location and JobTitle or CommonEntity, but its doesn't work
Controller:
public class HelloController: Controller
{
[HttpGet]
public IActionResult Index()
{
var locations = new List<Location>()
{
new Location()
{
Id = 0,
Title = "Russia"
},
new Location()
{
Id = 1,
Title = "Canada"
}
};
ViewBag.Location = locations;
var jobs = new List<JobTitle>()
{
new JobsTitle()
{
Id = 0,
Title = "Manager"
} ,
new JobsTitle()
{
Id = 1,
Title = "Programmer"
}
};
ViewBag.JobTitle = new SelectList(jobs, "Title", "Title");
return View();
}
[HttpPost]
public string Find(string answer1, string answer2)
{
return "Fine";
}
View:
#using Stargate.Core.Models.CoreEntities
#model CommonEntity
#using (Html.BeginForm())
{
#Html.DropDownListFor(m => m.Location.Title, new SelectList(ViewBag.Location, "Title", "Title"))
#Html.DropDownListFor(m => m.JobTitle.Title, new SelectList(ViewBag.JobTitle, "Title", "Title"))
<button type="submit">Find</button>
}
Models:
public class CommonEntity
{
public Location Location { get; set; }
public JobTitle JobTitle { get; set; }
}
public class JobTitle
{
public long Id { get; set; }
public string Title { get; set; }
}
public class Location
{
public long Id { get; set; }
public string Title { get; set; }
}
Because the parameter names you accept are answer1, answer2, you should have a matching name in your view to make it possible to bind successfully.
You can modify your front-end code as follows(DropDownListForto DropDownList):
#model CommonEntity
#using (Html.BeginForm("Find", "Hello"))
{
#Html.DropDownList("answer1", new SelectList(ViewBag.Location, "Title", "Title"))
#Html.DropDownList("answer2", new SelectList(ViewBag.JobTitle, "Title", "Title"))
<button type="submit">Find</button>
}
Your Controller:
public class HelloController : Controller
{
[HttpGet]
public IActionResult Index()
{
var locations = new List<Location>()
{
new Location()
{
Id = 0,
Title = "Russia"
},
new Location()
{
Id = 1,
Title = "Canada"
}
};
ViewBag.Location = locations;
var jobs = new List<JobTitle>()
{
new JobTitle()
{
Id = 0,
Title = "Manager"
} ,
new JobTitle()
{
Id = 1,
Title = "Programmer"
}
};
ViewBag.JobTitle = jobs;
return View();
}
[HttpPost]
public string Find(string answer1,string answer2)
{
return "Fine";
}
}
Class:
public class CommonEntity
{
public Location Location { get; set; }
public JobTitle JobTitle { get; set; }
}
public class JobTitle
{
public long Id { get; set; }
public string Title { get; set; }
}
public class Location
{
public long Id { get; set; }
public string Title { get; set; }
}
Result:
you are doing things wrongly,
you should correct your cshtml so that when submitting the form, it will target your Find Action,
#using (Html.BeginForm("Find", "Hello"))
In your Find Action you should provide in input args resolvable by the DefaultModelBinder, since you don't have a ViewModel to intercept the response, I would suggest that you recieve a FormCollection and you can access your values from there.
[HttpPost]
public string Find(FormCollection form)
{
return "Fine";
}
Try updating parameters as below. Please refer Model Binding in ASP.NET Core for more details.
[HttpPost]
public string Find(Location Location, JobTitle JobTitle)
{
return "Fine";
}
Or you can try with parameter of CommonEntity like below.
[HttpPost]
public string Find(CommonEntity commonEntity)
{
var locationTitle = commonEntity.Location.Title;
var jobTitle = commonEntity.JobTitle.Title;
return "Fine";
}
I have a ProductController with an Edit Action GetRequest and an Edit Action PostRequest .
The Edit GetRequest Action gets an individual Product entity based on route ID value from the request and builds a ProductViewModel. I have implicit conversion methods for these.
The View returned builds a ProductEditViewModel with the values fro the ProductViewModel:
// GET: Product/Edit/5
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
ProductViewModel product = await db.Products.FindAsync(id);
var categoryID = db.Categories.Single(c => c.Products.Any(p => p.Id == id)).Id;
if (product == null)
{
return HttpNotFound();
}
return View(new ProductEditViewModel { Id = product.Id, Name = product.Name, ByteImage = product.ByteImage, Price = product.Price, CategoryId = categoryID});
}
I have access to the Edit GetRequest page when running my applicion and can see a Product displayed successfully to edit, however, when I send back a Post request, the ProductEditViewModel that is given to the Edit PostRequest Action is empty. It should have the Name and Id properties filled in as the Image can be left unchanged. Here is my Edit PostRequest Action:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "Id,Name,Image,Price")] ProductEditViewModel model)
{
var oldImage = db.Products.Where(p => p.Id == model.Id).Select(x => x.Image).FirstOrDefault();
if (ModelState.IsValid)
{
Product modifiedProduct = model;
if(modifiedProduct.Image == null)
{
modifiedProduct.Image = oldImage;
}
db.Entry(modifiedProduct).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index/" + model.categoryID);
}
return View(model);
}
My ProductViewModels:
public class ProductViewModel
{
public int Id { get; set; }
[Required, Display(Name="Product Name")]
public string Name { get; set; }
[DataType(DataType.Upload)]
public HttpPostedFileBase Image { get; set; }
public string OutputImage { get; set; }
public Byte[] ByteImage { get; set; }
[Required]
public Decimal Price { get; set; }
public int CategoryId { get; set; }
public static byte[] ConvertToByte(ProductViewModel model)
{
if (model.Image != null)
{
byte[] imageByte = null;
BinaryReader rdr = new BinaryReader(model.Image.InputStream);
imageByte = rdr.ReadBytes((int)model.Image.ContentLength);
return imageByte;
}
return null;
}
// ViewModel => Model | Implicit type Operator
public static implicit operator Product(ProductViewModel viewModel)
{
var model = new Product
{
Id = viewModel.Id,
Name = viewModel.Name,
Image = ConvertToByte(viewModel),
Price = viewModel.Price
};
return model;
}
// Model => ViewModel | Implicit type Operator
public static implicit operator ProductViewModel(Product model)
{
var viewModel = new ProductViewModel
{
Id = model.Id,
Name = model.Name,
OutputImage = string.Format("data:image/jpg;base64,{0}", Convert.ToBase64String(model.Image)),
ByteImage = model.Image,
Price = model.Price,
CategoryId = model.Id
};
return viewModel;
}
}
ProductEditViewModel:
public class ProductEditViewModel
{
public int Id { get; set; }
[Required, Display(Name = "Product Name")]
public string Name { get; set; }
[DataType(DataType.Upload)]
public HttpPostedFileBase Image { get; set; }
public string OutputImage { get; set; }
public byte[] ByteImage { get; set; }
[Required]
public decimal Price { get; set; }
public int? CategoryId { get; set; }
public static implicit operator ProductViewModel(ProductEditViewModel viewModel)
{
var model = new Product
{
Id = viewModel.Id,
Name = viewModel.Name,
Image = ConvertToByte(viewModel),
Price = viewModel.Price
};
return model;
}
public static implicit operator ProductEditViewModel(ProductViewModel viewModel)
{
var model = new ProductEditViewModel
{
Id = viewModel.Id,
Name = viewModel.Name,
ByteImage = ConvertToByte(viewModel),
Price = viewModel.Price
};
return model;
}
private static byte[] ConvertToByte(ProductEditViewModel viewModel)
{
if (viewModel.Image != null)
{
byte[] imageByte = null;
BinaryReader rdr = new BinaryReader(viewModel.Image.InputStream);
imageByte = rdr.ReadBytes((int)viewModel.Image.ContentLength);
return imageByte;
}
return null;
}
}
I didn't have the getters and setters for the ProductEditViewModel to be able to assign values.
I made a dropdown list for me to assign Admin Roles to certain users when I create them:
But they don't assign themselves properly, as you can see here:
It happens because of this line Value = "Administrator LVL2". My question is: How do i assign it to my model like I've done for assigning last names:
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
Views\User\Create.cshtml
<div class="editor-label">
#{
List<SelectListItem> listItems = new List<SelectListItem>();
listItems.Add(new SelectListItem
{
Text = "Administrator LVL1",
Value = model => model.AdminRole, <-- THIS IS WRONG
});
listItems.Add(new SelectListItem
{
Text = "Administrator LVL2",
Value = "Administrator LVL2",
Selected = true
});
listItems.Add(new SelectListItem
{
Text = "Administrator LVL3",
Value = "Administrator LVL3"
});
}
#Html.DropDownListFor(model => model.AdminRole, listItems, "-- Select Admin Role --")
</div>
UserController.cs
public class UserController : Controller
{
private IssueContext db = new IssueContext();
//
// GET: /User/
public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = searchString;
var users = from s in db.Users
select s;
if (!String.IsNullOrEmpty(searchString))
{
users = users.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
|| s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
}
switch (sortOrder)
{
case "name_desc":
users = users.OrderByDescending(s => s.LastName);
break;
case "Date":
users = users.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
users = users.OrderByDescending(s => s.EnrollmentDate);
break;
default: // Name ascending
users = users.OrderBy(s => s.LastName);
break;
}
int pageSize = 5;
int pageNumber = (page ?? 1);
return View(users.ToPagedList(pageNumber, pageSize));
}
//
// GET: /User/Details/5
public ActionResult Details(int id = 0)
{
User user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
//
// GET: /User/Create
public ActionResult Create()
{
return View();
}
//
// POST: /User/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(
[Bind(Include = "LastName, FirstMidName, EnrollmentDate, DepartmentID, DepotID")]
User user)
{
try
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(user);
}
//
// GET: /User/Edit/5
public ActionResult Edit(int id = 0)
{
User user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
//
// POST: /User/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
[Bind(Include = "UserID, LastName, FirstMidName, EnrollmentDate, DepartmentID, DepotID")]
User user)
{
try
{
if (ModelState.IsValid)
{
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(user);
}
//
// GET: /User/Delete/5
//This code accepts an optional Boolean parameter that indicates whether it was called after a failure to save changes.
//This parameter is false when the HttpGet Delete method is called without a previous failure. When it is called by the
//HttpPost Delete method in response to a database update error, the parameter is true and an error message is passed to the view.
public ActionResult Delete(bool? saveChangesError = false, int id = 0)
{
if (saveChangesError.GetValueOrDefault())
{
ViewBag.ErrorMessage = "Delete failed. Try again, and if the problem persists see your system administrator.";
}
User user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
//
// POST: /User/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id)
{
try
{
User user = db.Users.Find(id);
db.Users.Remove(user);
db.SaveChanges();
}
catch (DataException/* dex */)
{
// uncomment dex and log error.
return RedirectToAction("Delete", new { id = id, saveChangesError = true });
}
return RedirectToAction("Index");
}
//To make sure that database connections are properly closed and the resources they hold freed up, you should see to it that the context instance is disposed.
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
How my classes are mapped:
User to Admin is 1 to 0..1 (I can assign some users with admin status but I don't want every user to have it)
Admin to Ticket is 1 to Many(You can only assign 1 admin(to fix the issue) to a ticket)
User to Ticket is 1 to many (One user can create multiple tickets)
User.cs
public class User
{
public int UserID { get; set; }
[StringLength(50, MinimumLength = 1)]
public string LastName { get; set; }
[StringLength(50, MinimumLength = 1, ErrorMessage = "First name cannot be longer than 50 characters.")]
[Column("FirstName")]
public string FirstMidName { get; set; }
public string FullName
{
get { return LastName + ", " + FirstMidName; }
}
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
public int? AdministratorID { get; set; }
[ForeignKey("AdministratorID")]
public virtual Administrator Administrator { get; set; }
public int DepartmentID { get; set; }
[ForeignKey("DepartmentID")]
public virtual Department Department { get; set; }
public int DepotID { get; set; }
[ForeignKey("DepotID")]
public virtual Depot Depot { get; set; }
public virtual ICollection<Ticket> Tickets { get; set; }
}
Ticket.cs
public class Ticket
{
public int TicketID { get; set; }
public string Issue { get; set; }
[DisplayFormat(NullDisplayText = "No Priority")]
public Priority? Priority { get; set; }
[ForeignKey("CategoryID")]
public virtual Category Category { get; set; }
public int CategoryID { get; set; }
public int UserID { get; set; }
[ForeignKey("UserID")]
public virtual User User { get; set; }
public int AdministratorID { get; set; }
[ForeignKey("AdministratorID")]
public virtual Administrator Administrator { get; set; }
}
Administrator.cs
public class Administrator
{
public int AdministratorID { get; set; }
public string AdministratorTitle { get; set; }
public virtual ICollection<User> Users { get; set; }
}
Here is what I would recommend:
1) Make a Roles Table (if you have done ASP.NET Membership, this is already provided).
Role:
RoleId Int
RoleName String
2) Add Roles into the table (you can use SQL Server [or any SQL you are using])
3) Add a ForeignKey to your User OR add a link table like UsersInRoles (once again, if you used ASP Membership this is added)
1st Example:
User:
UserId Int
FirstName String
LastName string
DepotId Int
DepartmentId Int
RoleId Int
2nd Example:
UsersInRole
UserId Int
RoleId Int
Now once you GET a user, you can bring back the RoleId:
public ActionResult List()
{
// Get Roles
ViewBag.Roles = (from role in dbContext.Roles
select new SelectListItem
{
Text = role.RoleName,
Value = role.RoleId
});
// Get Users
IEnumerable<User> users = (from user in dbContext.Users
select new User
{
UserId = user.UserId,
FirstName = user.FirstName,
LastName = user.LastName,
DepotId = user.DepotId,
DepartmentId = user.DepartmentId,
RoleId = user.RoleId,
// OR
// RoleId = dbContext.Roles.Where(r => r.UserId == user.UserId).First().RoleId
//
});
return users;
}
In your view:
<div>
#Html.DropDownListFor(model => model.RoleId, (SelectList)ViewBag.Roles)
</div>
if you have 2 tables in your database.. one that holds the User Info (for arguments sake the name of the table will be User), and the other that holds the possible roles (name of table is Role).. you can create a property in the User table called roleID(foreign key) to hold the Primary Key (ID) of the Role Table. So in the Role table let's say you have 2 properties, ID and text. The ID holds the unique value to represent the text. e.g ID = 1, text = Administrator... ID = 2, text = Member... so on and so on... then when you create a user, based on the example you gave above, you would see this is your User table test 2 test2 2016-11-03 1 1 1 //if you made him an administator
In your Details view you can display the text and not the ID by making sure that in your User model you have public virtual Role role { get; set; }
Then:
#Html.DisplayNameFor(model => model.Role.text)
Then in your User Controller under the Create Action you stuff the possible roles in a ViewBag:
public ActionResult Create()
{
ViewBag.roleID = new SelectList(database.Role, "ID", "text");
return View()
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID, firstName, lastName, enrollmentDate, departmentID, depotID, roleID")] User user)
{
if(ModelState.IsValid)
{
ViewBag.roleID = new SelectList(database.Role, "ID", "text", user.roleID);
return View(user);
}
}
Then in your Create cshtml page :
#Html.DropDownList("roleID", null, htmlAttributes: new { #class = "form-control" })
assuming you are using bootstrap for the form-control class name.
I've made a Profile Model that stores certain property values. Such as firstName, lastName... etc... Among others state is one of them.
Now problem occurred when I've replaced TextBox with DropDownList for State property.
This is the way I've made my Edit method in ProfileController.
When opened app will populate if any existing values. First issue, how to get selected value from the dropdown, so i can pass it into Profile property like I did in this method.
public ActionResult Edit(string username)
{
ViewBag.StateID = new SelectList(db.States, "StateID", "StateName");
ProfileBase _userProfile = ProfileBase.Create(username);
ProfileModel _profile = new ProfileModel();
System.Web.HttpContext.Current.Session["_userName"] = username;
if (_userProfile.LastUpdatedDate > DateTime.MinValue)
{
_profile.FirstName = Convert.ToString(_userProfile.GetPropertyValue("FirstName"));
_profile.LastName = Convert.ToString(_userProfile.GetPropertyValue("LastName"));
_profile.Address = Convert.ToString(_userProfile.GetPropertyValue("Address"));
_profile.City = Convert.ToString(_userProfile.GetPropertyValue("City"));
_profile.State = Convert.ToString(_userProfile.GetPropertyValue("State"));
_profile.Zip = Convert.ToString(_userProfile.GetPropertyValue("Zip"));
}
return View(_profile);
}
This worked fine when State was a string passed in TextBox, and then saved with Edit post method.
[HttpPost]
public ActionResult Edit(ProfileModel model)
{
if (ModelState.IsValid)
{
ProfileBase profile = ProfileBase.Create(System.Web.HttpContext.Current.Session["_userName"].ToString(), true);
if (profile != null)
{
profile.SetPropertyValue("FirstName", model.FirstName);
profile.SetPropertyValue("LastName", model.LastName);
profile.SetPropertyValue("Address", model.Address);
profile.SetPropertyValue("City", model.City);
profile.SetPropertyValue("State", model.State);
profile.SetPropertyValue("Zip", model.Zip);
profile.Save();
}
else
{
ModelState.AddModelError("", "Error writing to Profile");
}
}
return RedirectToAction("Index");
}
This is how I created dropdown for State.
Model:
public class State
{
public int StateID { get; set; }
public string StateName { get; set; }
public IEnumerable<RegisterModel> RegModel { get; set; }
public IEnumerable<ProfileModel> Profiles { get; set; }
}
Controller:
ViewBag.StateID = new SelectList(db.States, "StateID", "StateName");
View:
#Html.DropDownList("StateID", (SelectList)ViewBag.StateID, new { #class = "dropdown" })
I've tried several things. No luck so far. What am I missing?!