MVC Master Detail Update - asp.net-mvc

I have created master detail form with editorfor templates, I am able to add new records but do not know how to update the child records while editing. I am able to see the phonenumbers in the controller.
Master Table : Person
Detail Table : PersonPhoneNumber
I need to update PersonPhoneNumbers before db.SaveChanges()
Model
public class Person
{
public Person()
{
this.PersonPhoneNumbers = new HashSet<PersonPhoneNumber>();
}
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<PersonPhoneNumber> PersonPhoneNumbers { get; set; }
public void BuildPhoneNumbers(int count = 1)
{
for (int i = 0; i < count; i++)
{
PersonPhoneNumbers.Add(new PersonPhoneNumber());
}
}
}
public class PersonPhoneNumber
{
public int PersonPhoneNumberId { get; set; }
public string PhoneNumber { get; set; }
public int PersonId { get; set; }
public bool DeletePhone { get; set; }
}
Controller
// GET: /Person/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Person person = db.Persons.Find(id);
if (person == null)
{
return HttpNotFound();
}
return View(person);
}
// POST: /Person/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Person person)
{
if (ModelState.IsValid)
{
db.Entry(person).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
Edit.cshtml
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Person</h4>
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.PersonId)
<div class="form-group">
#Html.LabelFor(model => model.FirstName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LastName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
</div>
<div>
<label>City</label>
#Html.EditorFor(model => model.PersonPhoneNumbers)
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
EditorTemplates
PersonPhoneNumber.cshtml
<div>
#Html.HiddenFor(model => model.PersonPhoneNumberId)
#Html.HiddenFor(model => model.PersonId)
</div>
<div class="form-group">
#Html.LabelFor(model => model.PhoneNumber, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PhoneNumber)
#Html.ValidationMessageFor(model => model.PhoneNumber)
</div>
</div>
Also please let me know is there any better way of doing the same.
Thanks

Try this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Person person)
{
if (ModelState.IsValid)
{
db.Entry(person).State = EntityState.Modified;
foreach (var phoneNumber in person.PersonPhoneNumbers)
db.Entry(phoneNumber).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}

Related

how can I pass the context from both the class in the MODEL to one view without this error?

In a MODEL, I have two class - ContentDetails and CompetencyDetails which contains its properties
namespace CompetencyAssessmentServices.ServiceModel
{
public class ContentDetails
{
public int CaseStudyId { get; set; }
public string CaseStudy { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public bool IsActive { get; set; }
public bool ReviewStatus { get; set; }
public string SolutionDescription { get; set; }
public int CompetencyID { get; set; }
public string CompetencyName { get; set; }
public List<string> SolutionId { get; set; }
}
public class CompetencyDetails
{
public int CompID { get; set; }
public string CompName { get; set; }
}
}
Controller :
Action CaseStudy is retrieving the list of CompetencyDetails from database which is working fine.
namespace CompetencyAssessment.Controllers
{
public class ContentManagementController : Controller
{
// GET: ContentManagement
IContentManagementRepository repo = new ContentManagementRepository();
[HttpGet]
public ActionResult CaseStudy()
{
List<CompetencyDetails> complst = repo.GetCompetencyDetails();
ViewBag.list = complst;
return View(ViewBag.list);
}
[HttpPost]
public ActionResult CaseStudy(ContentDetails cd)
{
ContentDetails ctd = repo.CaseStudyCreationDetails(cd);
return View();
}
}
}
While loading the View, I am getting below error
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[CompetencyAssessmentServices.ServiceModel.CompetencyDetails]', but this dictionary requires a model item of type 'CompetencyAssessmentServices.ServiceModel.ContentDetails'.
View is
#model CompetencyAssessmentServices.ServiceModel.ContentDetails
#{
ViewBag.Title = "CASE-STUDY Contenet Creation (By SME)";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>CASE-STUDY Contenet Creation (By SME)</title>
</head>
<body>
#using (Html.BeginForm())
{
<h4>ContentDetails</h4>
<hr />
<div class="form-group">
#Html.LabelFor(model => model.CaseStudy, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.CaseStudy, new { htmlAttributes = new { #class = "form-control", style = "rows=20,columns=400" } })
#Html.ValidationMessageFor(model => model.CaseStudy, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.IsActive, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.IsActive)
#Html.ValidationMessageFor(model => model.IsActive, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
Solution 1: #Html.TextBox("Sol1") #Html.DropDownList("CompetencyDetails", new SelectList(ViewBag.list, "CompID", "CompName"), "Select Competency")
Solution 2: #Html.TextBox("Sol2") #Html.DropDownList("CompetencyDetails", new SelectList(ViewBag.list, "CompID", "CompName"), "Select Competency")
Solution 3: #Html.TextBox("Sol3") #Html.DropDownList("CompetencyDetails", new SelectList(ViewBag.list, "CompID", "CompName"), "Select Competency")
Solution 4: #Html.TextBox("Sol4") #Html.DropDownList("CompetencyDetails", new SelectList(ViewBag.list, "CompID", "CompName"), "Select Competency")
<div class="form-group">
#Html.LabelFor(model => model.SolutionId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SolutionId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SolutionId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SolutionDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SolutionDescription, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SolutionDescription, "", 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>
}
</body>
</html>
The reason, I am getting this error because my view contains the reference from both class CompetencyDetails and ContentDetails
Can someone please help on how can I pass the context from both the class in the MODEL without this error ?
PS: This is my first MVC project so would appreciate any various approaches to achieve this
you can create new class having both the model class like example given below
public class Combine
{
public List<ContentDetails> ContentDetailsList { get; set; }
public ContentDetails ContentDetailsData { get; set; }
public List<CompetencyDetails> CompetencyDetailsInfoList { get; set; }
public CompetencyDetails CompetencyDetailsData { get; set; }
}
then in MVC controller
[HttpGet]
public ActionResult CaseStudy()
{
var caseStudy = new SupplierDTO()
{
ContentDetailsList = db.ContentDetails.ToList(),
CompetencyDetailsInfoList = db.CompetencyDetails.ToList(),
};
return View(caseStudy);
}
then MVC View
#model CompetencyAssessmentServices.Models.Combine
<div class="form-group">
#Html.LabelFor(model => model.ContentDetailsData.CaseStudy, htmlAttributes: new { #class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.ContentDetailsData.CaseStudy, new { htmlAttributes = new { #class = "form-control"} })
#Html.ValidationMessageFor(model => model.ContentDetailsData .CaseStudy, "", new { #class = "text-danger"})
</div>
</div>

Not able to retain original values after edit in mvc

i m not able to solve one issue that is , there are two files one is uploaded at the form filled up for the first time and the other file will be uploaded when the form willl be edited , but the issue is that, when the first uploaded file is shown in edit and no changes be made, that files gets blank , i used exclude as well but that does not made any effect.
My Controller methods:
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
FileDetails fileDetails = db.FileUpload.Find(id);
if (fileDetails == null)
{
return HttpNotFound();
}
return View(fileDetails);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Exclude= "FileBeforeTour,FileBeforeTourName")] FileDetails fileDetails)
{
if (ModelState.IsValid)
{
string uploadedfilename = Path.GetFileName(fileDetails.fileaftertourupload.FileName);
if (!string.IsNullOrEmpty(uploadedfilename))
{
string filenamewithoutextension = Path.GetFileNameWithoutExtension(fileDetails.fileaftertourupload.FileName);
string extension = Path.GetExtension(fileDetails.fileaftertourupload.FileName);
string filename = filenamewithoutextension + DateTime.Now.ToString("yymmssfff") + extension;
fileDetails.FileAfterTourName = filename;
fileDetails.FileAfterTour = "~/Content/Files/" + filename;
filename = Path.Combine(Server.MapPath("~/Content/Files"), filename);
fileDetails.fileaftertourupload.SaveAs(filename);
db.Entry(fileDetails).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(fileDetails);
}
My Edit View:
#model OnlineStationaryRegister.Models.FileDetails
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm("Edit", "File", FormMethod.Post, new { #enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>FileDetails</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.FileId)
<div class="form-group">
#Html.LabelFor(model => model.Officername, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Officername, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Officername, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Designation, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Designation, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Designation, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.FileBeforeTour, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
View File
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.FileAfterTour, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="file" name="fileaftertourupload" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
My FileDetails model:
namespace OnlineStationaryRegister.Models
{
public class FileDetails
{
[Key]
public int FileId { get; set; }
public string Officername { get; set; }
public string Designation { get; set; }
public string FileBeforeTour { get; set; }
public string FileAfterTour { get; set; }
public string FileBeforeTourName { get; set; }
public string FileAfterTourName { get; set; }
public int status { get; set; } = 1;
[NotMapped]
public HttpPostedFileBase filebeforetourupload { get; set; }
[NotMapped]
public HttpPostedFileBase fileaftertourupload { get; set; }
}
}
It can be solved in many ways. One of the simplest ways as follows:
db.Entry(fileDetails).State = EntityState.Modified;
db.Entry(fileDetails).Property(x => x.FileBeforeTourName).IsModified = false; //<-- Here it is
db.Entry(fileDetails).Property(x => x.FileBeforeTour).IsModified = false; //<-- Here it is
db.SaveChanges();

Only defualt values passed to database

I'm pretty new to programming and I'm strugling with quite simple "Create" controller and view.
In the view user is declaring values, which should be passed to database. Here's the model:
public class Expense
{
public int ExpenseID { get; set; }
[DisplayName("Data")]
[Column(TypeName = "DateTime2")]
public DateTime Date { get; set; }
[DisplayName("Wartość")]
public decimal Amount { get; set; }
[DisplayName("Opis")]
public string Details { get; set; }
[DisplayName("Rodzaj")]
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string Name { get; set; }
public virtual ICollection<Expense> Expenses { get; set; }
}
In the same view I want to include partial view for managing the categories (adding, removing).
To have this working I've implemented ViewModel:
public class ExpenseCreateViewModel
{
public Expense ExpenseCreate { get; set; }
public Category CategoryCreate { get; set; }
}
And here's the code for my View:
#model Wydatki2._0.Models.ExpenseCreateViewModel
#{
ViewBag.Title = "Create";
}
<h2>Dodaj wydatek</h2>
<table class="table">
<tr>
<th>
<div>
#using (Html.BeginForm("CreateExpense", "ExpenseCreate", FormMethod.Post, new { }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.ExpenseCreate.CategoryID, "Rodzaj", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CategoryID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.ExpenseCreate.CategoryID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ExpenseCreate.Amount, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ExpenseCreate.Amount, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ExpenseCreate.Amount, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ExpenseCreate.Date, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ExpenseCreate.Date, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ExpenseCreate.Date, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ExpenseCreate.Details, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ExpenseCreate.Details, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ExpenseCreate.Details, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Dodaj" class="btn btn-default" />
</div>
</div>
</div>
}
</div>
</th>
<th>
<div>
<input type="button" id="btn" class="btn btn-default" value="Dodaj/Usuń Kategorię" />
<p class="error">#ViewBag.Warning</p>
</div>
<div id="Create" style="display:none">
#Html.Partial("CreateCategory", Model.CategoryCreate)
</div>
</th>
</tr>
</table>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/toggle")
}
The problem is that when I submit the form only the CategoryID value is passed correctly. The rest of parameters have just default values. The partial view is working well - I'm able to add or remove categories, which then are passed to the main view.
The code for my Controller:
namespace Wydatki2._0.Controllers
{
public class ExpenseCreateController : Controller
{
private WydatkiContext db = new WydatkiContext();
public ActionResult Create(bool? warn = false)
{
ExpenseCreateViewModel model = new ExpenseCreateViewModel()
{
ExpenseCreate = new Expense(),
CategoryCreate = new Category()
};
var query = from b in db.Categories
where b.CategoryID != 1
select b;
if (warn.GetValueOrDefault())
{
ViewBag.Warning = "Nie możesz usunąć tej kategorii.";
}
ViewBag.CategoryID = new SelectList(query, "CategoryID", "Name");
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateExpense([Bind(Include = "ExpenseID,Date,Amount,Details,CategoryID")] Expense expense)
{
if (ModelState.IsValid)
{
db.Expenses.Add(expense);
db.SaveChanges();
return RedirectToAction("Create");
}
var query = from b in db.Categories
where b.CategoryID != 1
select b;
ViewBag.CategoryID = new SelectList(query, "CategoryID", "Name", expense.CategoryID);
return View(expense);
}
public ActionResult CreateCategory()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateCategory([Bind(Include = "CategoryID,Name")] Category category)
{
if (ModelState.IsValid)
{
Category cat = db.Categories.FirstOrDefault(c => c.Name== category.Name);
if (cat != null)
{
if (cat.CategoryID == 1 || cat.CategoryID ==2)
{
return RedirectToAction("Create", new { warn = true });
}
else
{
db.Categories.Remove(cat);
db.SaveChanges();
return RedirectToAction("Create");
}
}
else
{
db.Categories.Add(category);
db.SaveChanges();
return RedirectToAction("Create");
}
}
return View(category);
}
I'm inclined to believe that the problem is caused by the model, which I'm passing to the view, but I really don't know, how to pass it correctly... Anyone could help with this?
You should use
([Bind(Prefix="prefixhere")]Category category)
I assume your prefix should be CategoryCreate for category, which the extension from your model ExpenseCreateViewModel, same for your CreateExpense, your prefix should be ExpenseCreate, this way you tell your controller to expect your input names after this prefix, so it will look for CategoryID and Name in create category action after the prefix you passed.
Something Like this
([Bind(Prefix="CategoryCreate")]Category category)
([Bind(Prefix="ExpenseCreate")]Expense expense)

ASP NET MVC 5 SeletList DropDownList

I have some problems with SelectList and DropDownList.
Ich have the two Models (TimeRecord has a navigation-property to Project):
public class Project
{
public int ProjectId { get; set; }
[Required]
public string ProjectName { get; set; }
}
and
public class TimeRecord
{
public int TimeRecordId { get; set; }
public int ProjectId { get; set; }
public string Description { get; set; }
public Project TmRecProject { get; set; }
}
In my Controller in the Create-action method the SelectList is pass by ViewBag to the View (till now all is correct working)
public ActionResult Create()
{
ViewBag.ProjectId = new SelectList(db.Projects, "ProjectId", "ProjectName");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(TimeRecord timeRecord)
{
if (ModelState.IsValid)
{
db.TimeRecords.Add(timeRecord);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(timeRecord);
}
Here is the View:
#model SelectListDropDownTest.Models.TimeRecord
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>TimeRecord</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.TmRecProject.ProjectId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("ProjectId", null, new { #class = "form-control" } )
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Description, "", 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>
}
In the Create-View I can select a Project from the DropDownList. My Problem is when I pass the Model "TimeRecord" back to the Controller the Project "TmRecProject" is always null.
What is the best way to solve this Problem?
First of all I am not able to understand how are you able to select value from dropdown list as you have not bind your 'ViewBag.ProjectId' with your drop down list.
Change in your view and your code will start working !!!!
Change:
Bind the drop down list with the model in View.
#Html.DropDownListFor(model => model.TmRecProject.ProjectId, ViewBag.ProjectId as IEnumerable<SelectListItem>, new { #class = "form-control" })
Others are as it is and you will get data on your post method.

Bind Checkboxlist to model

I'm working on an app for a cycling team. I have to add riders to a ride. To do this I want the user te select the date of a ride, select a value for the point of this ride an then have a list of the members of the team where the user selects which member participated on the ride.
It works fine until I post the form. when I debug my model in the controler the list of Riders in de model counts 4 riders (which is correct as I have 4 riders in my Db for testing) but the riders are null when I check the list.
Can anyone help me, I dont know what I'm doing wrong.
this are the viewmodels I use:
public class RiderViewModel
{
public string Id { get; set; }
public string FulllName { get; set; }
public bool IsChecked { get; set; }
}
public class RideViewModel
{
public string RideId { get; set; }
[Display(Name = "Datum")]
[DataType(DataType.Date)]
[Required(ErrorMessage = "Datum is verplicht")]
public DateTime Date { get; set; }
[Display(Name = "Aantal punten")]
[Required(ErrorMessage = "Een waarde voor het puntenaantal is verplicht")]
public int Punten { get; set; }
[Display(Name = "Leden")]
public List<RiderViewModel> Riders { get; set; }
}
this is my controler:
//POST Rides/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(RideViewModel model)
{
if (ModelState.IsValid)
{
var db = new ApplicationDbContext();
var riders = new List<ApplicationUser>();
foreach(RiderViewModel r in model.Riders)
{
var user = db.Users.FirstOrDefault(u => u.Id == r.Id);
if(user == null)
{
ModelState.AddModelError(string.Empty, "Er is een Fout opgetreden bij het selecteren van de leden. contacteer de systeembeheerder indien het probleem blijft bestaan");
return View(model);
}
riders.Add(user);
}
var ride = new Ride
{
Date = model.Date,
Punten = model.Punten,
Riders = riders
};
db.Rides.Add(ride);
db.SaveChanges();
return RedirectToAction("Index", "AdminPanel");
}
return View(model);
}
and this is the view:
using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Ride</h4>
<hr />
<div class="form-group">
#Html.LabelFor(model => model.Date, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Date, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Date, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Punten, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Punten, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Punten, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.Label("Leden", htmlAttributes: new { #class = "control-label col-md-2"})
<div class="col-md-10">
#for (var i = 0; i < Model.Riders.Count(); i++)
{
<div class="col-md-10">
#Html.HiddenFor(model => model.Riders[i])
#Html.CheckBoxFor(model => model.Riders[i].IsChecked)
#Html.LabelFor(model => model.Riders[i].IsChecked, Model.Riders[i].FulllName)
</div>
}
</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>
}
Thanx a lot.
grtz Jeff
You can use a EditorTemplate for this, just add a new file in the EditorTemplates folder named RiderViewModel :
#model RiderViewModel
<div class="col-md-10">
#Html.HiddenFor(model => model.Id)
#Html.CheckBoxFor(model => model.IsChecked)
#Html.LabelFor(model => model.IsChecked, Model.FulllName)
</div>
Then in the view just call the EditorFor:
#Html.EditorFor(m => m.Riders)
Your usage of
#Html.HiddenFor(model => model.Riders[i])
is creating a hidden input for a complex property which is typeof RiderViewModel. If you inspect the html, it will be something like
<input type="hidden" id="Riders_0_" name="Riders[0]" value="someAssembly.RiderViewModel" />
When you submit, the DefaultModelBinder tries to set model.Riders[0] to the value someAssembly.RiderViewModel which fails and so model.Riders[0] is null
Assuming you want to generate a hidden input for the ID property, change it to
#Html.HiddenFor(model => model.Riders[i].ID)

Resources