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).
Related
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.
I am working on an ASP.Net core application and would like to align some text in a string.
Somehow I am not able to get this working and am probably missing something very obvious here.
So this is my code (simplified):
public class AdminController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ImportOrganizations(ICollection<IFormFile> files)
{
var count = 0;
var uploads = Path.Combine(_environment.WebRootPath, "uploads");
foreach (var file in files)
{
if (file.Length <= 0) continue;
using (var reader = new StreamReader(file.OpenReadStream()))
{
var csv = new CsvReader(reader);
while (csv.Read())
{
// Fields that need to be filled
string name;
try
{
name = csv.GetField<string>("Name");
}
catch (Exception ex)
{
ModelState.AddModelError("", $"Row {csv.Row, 10}, {ex.Message}");
continue;
}
// Check if name has a value
if (string.IsNullOrWhiteSpace(name))
{
ModelState.AddModelError("", $"Row {csv.Row, 10}, Name is a required field");
continue;
}
if (await _context.Organizations.AnyAsync(o => o.Name == name))
{
ModelState.AddModelError("", $"Row {csv.Row, 3}, Organization {name} already exists");
continue;
}
// Add the new Event
var or = new Organization()
{
Name = name
};
_context.Organizations.Add(or);
}
await SaveContext();
}
}
var model = new ImportViewModel("Import Organizations", nameof(ImportOrganizations), count);
return View("Import", model);
}
}
Now when the import file does not have a value in the name field, I expect something like this in my browser:
Row 20 , Name is a required field
But I keep getting this:
Row 20, Name is a required field
Could someone help me out here?
You need to use negative value for the field width, if you want to pad value on the right side:
$"Row {csv.Row, -10}, {ex.Message}"
See Composite Formatting article for more details.
Thanks to the comment of sgmoore, I was able to resolve it.
It seems this is an issue of html, where it is not possible to use multiple whitespaces in a row.
i'm trying to add multiple textbox values to database it is working on just single textbox row but now working when i'm adding multiple rows of textboxes. i'm sharing what i have done so far.
Action Method:
public async Task<ActionResult> Create(FormCollection values)
{
var customer = new Customer();
var model = new TicketViewModel();
TryUpdateModel(model.TicketDetail);
try
{
foreach (var ticket in model.Tickets)
{
ticket.Date = DateTime.Now;
ticket.ProcessId = DateTime.Now.Ticks.ToString().Substring(12, 6);
ticket.CreationMethod = "Manual";
ticket.isCustomer = User.IsInRole("Customer") ? true : false;
ticket.Total = 0;
ticket.Email = model.TicketDetail.Ticket.Email;
customer.City = "Not Specified";
customer.Country = "Not SPecified";
customer.Image = "~/Images/nopic.jpg";
customer.Password = System.Web.Security.Membership.GeneratePassword(11, 3);
customer.IsActive = true;
customer.CreationMethod = "Manual";
customer.DateAdded = DateTime.Now;
customer.Email = ticket.Email;
customer.FirstMidName = string.IsNullOrEmpty(ticket.FullName) ? "Not Specified" : ticket.FullName;
customer.LastName = "Not Specified";
customer.Salutation = "Not Specified";
customer.UserName = DateTime.Now.Ticks.ToString().Substring(3, 9);
//ticket detail
var abcd = values["abcd"].ToString();
var getID = await db.Parts.Where(c => c.PartNumber == abcd)
.FirstOrDefaultAsync();
model.TicketDetail.GenericOrderId = ticket.GenericOrderId;
model.TicketDetail.PersonID = customer.PersonID;
model.TicketDetail.Status = "New";
model.TicketDetail.PartId = getID.PartId;
model.TicketDetail.Ticket.Date = DateTime.Now;
}
try
{
// db.Tickets.Add(ticket);
db.Customers.Add(customer);
db.TicketDetails.Add(model.TicketDetail);
}
catch (Exception ex)
{
ViewBag.PartId = new SelectList(db.Parts.Take(5), "PartId", "Name");
ModelState.AddModelError("", string.Format(ex.Message + "\n" + ex.InnerException));
return View(model.TicketDetail);
}
// Save all changes
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
catch(Exception ex)
{
ModelState.AddModelError("", String.Format(ex.Message + "\n" + ex.InnerException));
//Invalid - redisplay with errors
return View(model.TicketDetail);
}
}
ViewModel:
public class TicketViewModel
{
public TicketViewModel()
{
TicketDetails = new List<TicketDetail>();
TicketDetail = new TicketDetail();
Ticket = new Ticket();
Tickets = new List<Ticket>();
}
public virtual Ticket Ticket { get; set; }
public virtual IEnumerable<Ticket> Tickets { get; set; }
public virtual TicketDetail TicketDetail { get; set; }
public virtual IEnumerable<TicketDetail> TicketDetails { get; set; }
}
it is also giving error on this "TryUpdateModel(model.TicketDetail);" the error is value cannot be null, please guide me i'm stuck here i have searched internet but couldn't found any appropriate solution. i want to add multiple records
First all properties of your TicketViewModel class have to be instantiated.
To add multiple records (multiple Insert) you could use a StringBuilder and append the insert statements to it. You then have one big query string to be executed on your database.
If using values this is also a valid way:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
And loading the data to be inserted directly from a file is even faster.
Edit
(after down voting for no reason)
Because some people act like they know it all:
SQL injections are indeed a serious problem when dealing with Database access. That's no secret at all. A common technique to prevent the SQL query from being 'highjacked' you simply use the SQLCommand.Parameters property which is used to map each value individually to the statement to separate the query statement from the data (values) this way. It's now impossible to inject or manipulate statements whithout breaking them. And server side validation is standard to obtain maximum security as well as escaping special input characters and avoiding the use of privilegs with no or low restrictions.
This is NOT a wrong answer.
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();
}
}
i have a problem
in edit mode i bring user data and all data come normally
then i add that data to text fields on the page and that also work well
I'm sure from that as i see it in debug mode
but when the page come to the browser the password field is empty although i put the data on it
can any one tell me where is the problem ???
that is the code
method get data from data base
public AdminsContianer getContainer(int adminId)
{
using (Naqqab context = new Naqqab())
{
IQueryable<user> admin = getContainer_compiledQuery2.Invoke(context, adminId);
if (admin.Count() > 0)
{
var add = admin.FirstOrDefault();
if (add != null)
{
var rc = new AdminsContianer();
rc.FirstName = add.user_firstname;
rc.adminCreationdate = (DateTime)add.user_creationdate;
rc.LastName = add.user_lastname;
rc.Username = add.user_username;
rc.Password = add.user_password;
rc.adminLuState = add.user_lu_status.ToString();
rc.adminLuType = add.user_lu_type.ToString();
rc.adminLevel = add.admin_level.ToString();
rc.adminId = add.user_id;
return rc;
}
else
{
return null;
}
}
else
{
return null;
}
}
}
method put data in text fields
public void FillFormFields(AdminsContianer ad)
{
HiddenAdminID.Value = AdminIdToEdit;
registerAdminUsername.Text = ad.Username;
registerAdminLastname.Text = ad.LastName;
registerAdminFirstname.Text = ad.FirstName;
registerAdminPassword.Text = ad.Password;
registerAdminCPassword.Text = ad.Password;
adminLevelDropDownList.SelectedValue = ad.adminLevel.ToString();
//userTypeDropDownList.SelectedValue = ad.adminLuType.ToString();
registerAdminState.SelectedValue = ad.adminLuState.ToString();
}
thanks in advance
Use the following code to set value in password textbox registerAdminPasswod.Attributes.Add("value", ad.Password);
Why would you like to show the password because it can't be understand by the user.
Here is a solution its a code project link which has the solution
or
txt1.Text = "sample_password";
if (txt1.TextMode == TextBoxMode.Password)
{
txt1.Attributes.Add("value", txt1.Text);
}