I'm creating an application that books Guests in hotelrooms. In the HttpGet I pass a ReservationViewModel from my Controller to the View. This VM contains all the reservationdetails and 2 empty Guest objects (or however many). For each Guest object I show a form where the user needs to enter information about the Guest. However when I try to submit it only returns the info of one Guest. I've tried looking for a way to pass an array or multiple guests, but that doesn't seem to be possible, only sending one Guest object with parameters seems to work..
Here is the code for my GET:
[HttpGet]
public ActionResult Edit2(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Reservation reservation = resRepo.GetReservationByID(id);
ReservationVM reservationVM = new ReservationVM(0);
for (int i = 0; i < reservation.amount_people; i++)
{
reservationVM.guests.Add(new Guest());
}
foreach(Guest guest in reservationVM.guests)
{
guest.name = " ";
guest.zipcode = " ";
guest.housenumber = 0;
guest.suffix = "";
guest.email = " ";
guestRepo.AddGuest(guest);
}
guestRepo.Save();
reservationVM.date = (DateTime)reservation.date;
reservationVM.amount_people = (int)reservation.amount_people;
reservationVM.ID = reservation.ID;
reservationVM.room_ID = (int)reservation.room_ID;
if (reservation == null)
{
return HttpNotFound();
}
return View(reservationVM);
}
And my POST:
[HttpPost]
public ActionResult Edit2([Bind(Include = "room_ID,date,amount_people,ID")]Reservation reservation, [Bind(Include = "ID,name,zipcode,housenumber,suffix,email")]Guest guest)
{
if (ModelState.IsValid)
{
resRepo.UpdateReservation(reservation);
resRepo.Save();
guestRepo.UpdateGuest(guest);
guestRepo.Save();
Reservation r = new Reservation { ID = reservation.ID };
db.Reservations.Add(r);
db.Reservations.Attach(r);
Guest g = new Guest { ID = guest.ID };
db.Guests.Add(g);
db.Guests.Attach(g);
r.Guests.Add(g);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(reservation);
}
and my form for completion:
Form
Now I was wondering how to pass all the forminfo to my Controller and use that information to save the Reservation and each Guest, so I can write that to my db.
Thanks!
EDIT: I tried the solution given, but I can't seem to get the Guest information in my database. Problem seems to be that when it reaches the foreach loop to get the guests out of reservationVM it's empty. Tried writing to Debug output whenever it entered the loop but it never does. Here's my code
[HttpPost]
public ActionResult Edit2(ReservationVM reservationVM)
{
if (ModelState.IsValid)
{
//Get reservation
Reservation reservation = resRepo.GetReservationByID(reservationVM.ID);
//Update values in model
reservation.date = reservationVM.date;
reservation.amount_people = reservationVM.amount_people;
reservation.ID = reservationVM.ID;
reservation.room_ID = reservationVM.room_ID;
//Update to DB and save changes
resRepo.UpdateReservation(reservation);
resRepo.Save();
foreach (Guest guest in reservationVM.guests)
{
Guest temp = guestRepo.GetGuestByID(guest.ID);
temp.name = guest.name;
temp.zipcode = guest.zipcode;
temp.housenumber = guest.housenumber;
temp.suffix = guest.suffix;
temp.email = guest.email;
temp.ID = guest.ID;
guestRepo.UpdateGuest(temp);
reservation.Guests.Add(temp);
}
guestRepo.Save();
//Reservation r = new Reservation { ID = reservation.ID };
//db.Reservations.Add(r);
//db.Reservations.Attach(r);
//Guest g = new Guest { ID = guest.ID };
//db.Guests.Add(g);
//db.Guests.Attach(g);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(reservationVM);
}
You are passing ReservationVM from view to the post method. So write your post method as follows:
[HttpPost]
public ActionResult Edit2(ReservationVM reservationVM)
{
if (ModelState.IsValid)
{
// Here access the necessary values you need from `reservationVM` and do your necessary stuffs
return RedirectToAction("Index");
}
return View(reservation);
}
To get your guest information in you post action, you need to make the guest fields as follow:
#for(var i = 0; i < Model.guests.count; i++)
{
Your editor will be like below
#Html.EditorFor(model => model.guests[i].ID)
#Html.EditorFor(model => model.guests[i].name)
}
try making the fields in razor view like the above code .. it’ll work.
Related
I want to find the time at which Data is entered into my database. I'm using SQL Server as my database.
public class OtpchangeController : Controller
{
DateTime dbTime;
// GET: Otpchange
public ActionResult Generateotp()
{
return View();
}
[HttpPost]
public ActionResult Generateotp(tblPassword obj)
{
Random r = new Random();
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
tblPassword newObj = (from c in db.tblPasswords
where c.Username == obj.Username
select c).First();
if(newObj != null)
{
int num = r.Next();
string newOtp = num.ToString();
newObj.Otp = newOtp;
db.SaveChanges();
dbTime = DateTime.Now;
Session["Username"] = newObj.Username.ToString();
return RedirectToAction("ChangePassword");
}
}
return View();
}
public ActionResult ChangePassword()
{
return View();
}
[HttpPost]
public ActionResult ChangePassword(tblPassword obj)
{
string name = #Session["Username"].ToString();
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
tblPassword newObj = (from c in db.tblPasswords
where c.Otp == obj.Otp && c.Username == name
select c).First();
DateTime formTime = DateTime.Now;
TimeSpan result = dbTime.Subtract(formTime);
newObj.Password = obj.Password;
db.SaveChanges();
return RedirectToAction("Success");
}
//return View();
}
public ActionResult Success()
{
return View();
}
Here I want to find difference between the time when otp is added into database and the time when that otp is entered by the user.
But dbTime comes as 01/01/2001
But formTime is correct, also I want to find the difference between those time.
It seems the code you provided is not compiling or some parts are missing.
Anyway said I would suggest checking the msdn documentation about dbContext and its features here
You can delegate the database log to a console log or another more suitable provider(log4net or a simple custom log file). Those logs contain information about database execution times.
In your case you could do :
using (PasswordGenerationEntities db = new PasswordGenerationEntities())
{
db.Database.Log = Console.Write;
tblPassword newObj = (from c in db.tblPasswords
where c.Username == obj.Username
select c).First();
if(newObj != null)
{
int num = r.Next();
string newOtp = num.ToString();
newObj.Otp = newOtp;
db.SaveChanges();
dbTime = DateTime.Now;
Session["Username"] = newObj.Username.ToString();
return RedirectToAction("ChangePassword");
}
}
Check the console ouput.
Console Database info
I trying to update a Relation Table of my users with companies (providers). When i do update (first removing old related relations) and later adding selected.
The problem is that if not are debugged only add records but if debug step by step works Ok. Something is wierd but i dont know what.
this is the code
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "UsuarioId,Username,Password,Name,LastName,Email,IsActive, Matricula, Cuit,CP, AddressName,AddressNumber,Telefono1, Telefono2,Movil,destiny")] AppUsers_WrapperPOST applicationUser)
{
var companies = Request.Form["companies"];
if (String.IsNullOrWhiteSpace(companies))
{
ModelState.AddModelError("Companies", "One or more company is required");
return View();
}
if (ModelState.IsValid)
{
var companiesId = companies.Split(new char[] {','})
.Select(n = > Convert.ToInt32(n)).ToList();
var selectedCompanies = db.Companies.Where(
x = > companiesId.Contains(x.Id) && x.IsActive);
var usrList = db.AplicationUsers.Where(
x = > x.UserId == applicationUser.UserId).ToList();
AppUser usr = new AppUser();
if (usrList.Any())
{
usr = usrList.FirstOrDefault();
var companiesToAdd = selectedCompanies;
applicationUser.Companies = companiesToAdd;
CopyClass.CopyObject(applicationUser, ref usr);
db.Entry(usr).State = EntityState.Modified;
await db.SaveChangesAsync();
}
return RedirectToAction("Index");
}
return View(applicationUser);
}
I have searched here many times but I could not find what I want.
I am developing an application where I have USERS with specific Skills, and I want to relate them to specific project.
So I have the following tables: Users, UserSkills and more
My question is: I am using CRUD in MVC4, and when I open the EDIT view from the UserDetail Controller, in order to edit the user information, I need also to add (in the same Edit view) partial view, or any mechanism, where I list the user skills, using CheckBoxes to help in multi-selecting various skills for this user, and then when pressing "Save" it should store the User and UserSkills information back to the dB (MS-SQL).
I am using this Model:
public class SkillsViewModel
{
public IList<Skill> AvailableSkills { get; set; }
public IList<Skill> SelectedSkills { get; set; }
public SavedSkills SevedSkills { get; set; }
public User Usr { get; set; }
}
SavedSkills are the UserSkills Table, which will be used for the dB
AvailableSkills are the Skills Table
SelectedSkills are the ones that are selected in the Edit view
Keeping in mind that the Edit view also contain an image upload file:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(User Usr, HttpPostedFileBase file)
{
#region//validate file is selected
if (file != null)
{
if (file.ContentLength > (512 * 1000)) // 512 KB
{
ModelState.AddModelError("FileErrorMessage", "File size
must be within 512KB");
}
string[] allowedType = new string
[]"image/png", "image/gif",
"image/jpg", "image/jpeg" };
bool isFileTypeValid = false;
foreach (var i in allowedType)
{
if (file.ContentType == i.ToString())
{
isFileTypeValid = true;
break;
}
}
if (!isFileTypeValid)
{
ModelState.AddModelError
("FileErrorMessage", "Only .png,
.gif and .jpg file allowed");
}
}
#endregion
if (ModelState.IsValid)
{
if (Skk.Skk.Count (x => x.IsSelected) == 0)
{
//return "You have not selected any City";
}
else
{
StringBuilder sb = new StringBuilder();
sb.Append("You selected - ");
foreach (Skill skilll in Skk.Skk)
{
if (skilll.IsSelected)
{
sb.Append(skilll.SkillName + ", ");
}
}
//sb.Remove(sb.ToString().LastIndexOf(","), 1);
//return sb.ToString();
}
//Update User
if (file != null)
{
string savePath = Server.MapPath("~/Pictures");
string fileName = Guid.NewGuid() + Path.GetExtension
(file.FileName);
file.SaveAs(Path.Combine(savePath, fileName));
Usr.ImagePath = fileName;
}
using (dBEntities dc = new dBEntities())
{
var v = dc.Users.Where(a => a.Id.Equals
(Usr.Id)).FirstOrDefault();
if (v != null)
{
v.UserName = Usr.UserName;
v.Email = Usr.Email ;
v.StartDate = Usr.StartDate ;
v.Company = Usr.Company ;
v.Position = Usr.Position;
v.Division = Usr.Division ;
v.Department = Usr.Department ;
v.PM = Usr.PM ;
v.AM = Usr.AM;
v.Permissions = Usr.Permissions;
v.IsActive = Usr.IsActive;
if (file != null)
{
v.ImagePath = Usr.ImagePath ;
}
}
dc.SaveChanges();
}
return RedirectToAction("Index");
}
ViewBag.Department = new SelectList
(db.Departments, "DepID", "DepName", Usr.Department);
ViewBag.Division = new SelectList
(db.Divisions, "DivID", "DivName", Usr.Division);
ViewBag.Position = new SelectList
(db.Positions, "PosID","PosName", Usr.Position);
return View(Usr);
}
I hope I have explained it well, and thank you in advance.
I had same situation with you.
I was used chosen to add user's skills. IMHO, it more user friendly then using checkboxes (you can look chosen in action in linked-in, when you add your skills) when you have more than 20 skills in your database.
Chosen is regular HTML "select" tag with multiple attribute but more beautiful.
I also use Ajax JQuery to post my data to controller.
JQuery POST method also support send form data with attached file.
So you don't need to change your Edit action a lot. What you need is add parameter for selected skills (it's a string which separated by comma).
I am getting a 500 error when I post my AJAX form via clicking the submit button. The controller that handles the AJAX post is getting the data fine but when I return the Partial View, via this line, I am getting the 500:
return PartialView("_SiteSurveyNewClubTeam", model);
The reason I am returning the partial back instead of a HTTP status code is because if I don't, one of my dynamic dropdowns comes back unpopulated. Maybe I am pinting myself into a corner, here.
The data types supplied in the offending DropDownListFor() I believe are correct and in the right order: (string, IList<SelectListItem>)
Error
The ViewData item that has the key 'DistrictSelected' is of type 'System.String'
but must be of type 'IEnumerable<SelectListItem>'.
View Model Declarations
public IList<SelectListItem> DistrictSelect { get; set; }
public string DistrictSelected { get; set; }
Source of the Error is this line in my View
<span class="formColumn2">#Html.DropDownListFor(model => model.DistrictSelected, Model.DistrictSelect)</span>
Not sure why I am getting this. Any ideas?
Thanks
Here is the code that processes the AJAX form post
[HttpPost]
public ActionResult ProcessFormANewClubTeam(FormANewClubTeamViewModel model)
{
var httpStatus = HttpStatusCode.BadRequest;
var cosponsors = new List<NewClubSponsor>();
var errorMessages = new StringBuilder();
var tasks = new NewClubBuilderTasks();
var clubKeyNumber = tasks.GetClubKeyNumber();
var masterCustomerId = tasks.GetMasterCustomerId();
bool exceptionRaised = false;
if (ModelState.IsValid)
{
if (model.NewClub_Id > 0)
{
//Load the entity to be partially-updated
NewClub newClub = db.NewClubs.Single(nc => nc.Id == model.NewClub_Id);
//Set the values for the fields to be updated
newClub.District = model.DistrictSelected;
newClub.Division = model.DivisionSelected;
newClub.Region = Utility.Personify.GetRegionFromDistrict(newClub.District);
newClub.ClubCounselorMasterCustomerId = model.ClubCounselorMasterCustomerId;
newClub.ClubCounselorContact = model.ClubCounselorContact;
newClub.ClubCounselorEmail = model.ClubCounselorEmail;
newClub.ClubCounselorPhone = model.ClubCounselorPhone;
newClub.DateUpdated = DateTime.Now;
try
{
//Execute the UPDATE
var dbResult = db.SaveChanges() > 0;
httpStatus = HttpStatusCode.OK;
}
catch (SqlException ex)
{
//Catch exceptions here
}
// return new HttpStatusCodeResult((int) httpStatus);
return PartialView("_SiteSurveyNewClubTeam", model);
} else {
var errors = ModelState
.Where(x => x.Value.Errors.Count > 0)
.Select(x => new {x.Key, x.Value.Errors})
.ToArray();
return new HttpStatusCodeResult((int) httpStatus);
}
}
You have to repopulate your select list items in your DistrictSelect list in the post action. Your viewmodel that was posted has DistrictSelect as null, this is why you are getting that exception when you render your partial.
I have an MVC Application which displays items from a database. Each item has a Details and an Edit view. The Edit view allows you user to make changes to the record by displaying the values. The problem I am having is that I cannot get the changes that are made to save.
I believe that the first edit action result is used to display the records when the user clicks on "Edit" in the "Index" view. The second edit action result should be callled when the user presses the "Save Changes" button in the Edit view.
When debugging I did find that the values such as "item.Item_No_" where not being populated by the values in the View
I have provided code from my Controller,
Any help would be greatly appreciated,
Nick
public ActionResult Edit(string itemNo)
{
LinnWorksItemViewModel model = new LinnWorksItemViewModel(_data.Connection.ConnectionString, itemNo);
return View(model);
// Declare item no here?
foreach (string upload in Request.Files)
{
if (!Request.Files[upload].HasFile()) continue;
string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/";
string fileName = Path.GetFileName(Request.Files[upload].FileName);
Request.Files[upload].SaveAs(Path.Combine(path, fileName));
}
return View(model);
}
[HttpPost]
public ActionResult Edit(Item item, string itemNo)
{
LinnWorksItemViewModel model = new LinnWorksItemViewModel(_data.Connection.ConnectionString, itemNo);
try
{
Item _linnItem = _data.Items
.Where(x => x.Item_No_ == item.Item_No_)
.FirstOrDefault();
_linnItem.Description = item.Description;
_linnItem.Search_Description = item.Extended_Description;
_linnItem.Default_Barcode = item.Default_Barcode;
_linnItem.Variations_Group_Code = item.Variations_Group_Code;
_linnItem.LinnWork_Category_Code = item.LinnWork_Category_Code;
_linnItem.Unit_Cost = item.Unit_Cost;
_linnItem.Unit_Price = item.Unit_Price;
_linnItem.Shipping_Agent_Code = item.Shipping_Agent_Code;
_linnItem.Package_Group_Code = item.Package_Group_Code;
_linnItem.Stockkeeping_Units = item.Stockkeeping_Units;
_linnItem.Weight = item.Weight;
_linnItem.Width = item.Width;
_linnItem.Height = item.Height;
_linnItem.Depth = item.Depth;
_data.SubmitChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
string message = ex.Message;
return View();
}
}