Despite incorporating all advice I found in other questions and this article
the List vsValues passed to the view is always empty after POST.
View
#model OTS.ParcelOrder
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>ParcelOrder</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.otsID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.otsID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.otsID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.parcelID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.parcelID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.parcelID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.recipientCountry, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.recipientCountry, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.recipientCountry, "", new { #class = "text-danger" })
</div>
</div>
#for (int i = 0; i < Model.vsValues.Count; i++)
{
#Html.Label(Model.ParcelOrder_VSFields.ElementAt(i).VendorSpecifiedInfoField.fieldName,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.vsValues[i], new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.vsValues[i], "", new { #class = "text-danger" })
</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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Controller
// GET: ParcelOrders/Create
public ActionResult Create(int vendorId = 1)
{
ParcelOrder order = new ParcelOrder(vendorId);
return View(order);
}
// POST: ParcelOrders/Create
// Aktivieren Sie zum Schutz vor übermäßigem Senden von Angriffen die spezifischen Eigenschaften, mit denen eine Bindung erfolgen soll. Weitere Informationen
// finden Sie unter http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ParcelOrder parcelOrder)
{
parcelOrder.customerID = User.Identity.GetUserId();
if (ModelState.IsValid)
{
db.ParcelOrder.Add(parcelOrder);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(parcelOrder);
}
public partial class ParcelOrder
{
private Entities db = new Entities();
public List<string> vsValues = new List<string>();
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ParcelOrder()
{
this.ParcelOrder_VSFields = new List<ParcelOrder_VSFields>();
}
public ParcelOrder(int vendorId)
{
this.ParcelOrder_VSFields = new List<ParcelOrder_VSFields>();
var vendorQuery = from vsif in db.VendorSpecifiedInfoField
where vsif.vendorID == vendorId
select vsif;
foreach (var vsif in vendorQuery)
{
vsValues.Add("");
this.ParcelOrder_VSFields.Add(new OTS.ParcelOrder_VSFields
{
vsFieldID = vsif.id,
VendorSpecifiedInfoField = vsif,
value = ""
});
}
}
public string otsID { get; set; }
public string parcelID { get; set; }
public string customerID { get; set; }
public string recipientCountry { get; set; }
public virtual AspNetUsers AspNetUsers { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ParcelOrder_VSFields> ParcelOrder_VSFields { get; set; }
}
}
Note
The values are supposed to be POSTed in the List vsValues and will later be set as properties of ParcelOrder_VSFields inside the controller to avoid POSTing redundant information.
It's because you are posting nothing to no where look at that
#using (Html.BeginForm())
Should rather be like:
#using (Html.BeginForm("Create","ParcelOrders",FormMethod.Post))
Update
Also after that. Your Model looks wrong to me, if you want to pass values to a list i suggest you have a list property of same kind [this property needs to be with in your model ParcelOrder and not virtual]. then within the parameter-less constructor of the class do your foreach. track it within every step you see your issue.
Related
I am try to work on simple School management system using ASP .NET MVC 5 and SQL Server 2012 with database first approach.
The entity of student is related with an entity class, as every student would be enrolled in a class. SO have a 'Class' type variable and FK to the Classes table as attributes of my student entity.
Create View of Student has a dropdown list that shows the classes a student can be enrolled in. The dropdown is getting populated finely enough, but when the student is created and is viewed at the Index view, its class is NULL. When I checked the FK of created Students in Server Management studio, i found that the FK is being passed as NULL.
Can someone please let me know what I am doing wrong here.
PS. I am new to ASP .NET and I am not using a viewmodel because the tutorial I followed didn't and also because I didn't feel the need of making one.
Here is my Student.cs
using System;
using System.Collections.Generic;
public partial class Student
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Student()
{
this.Attendences = new HashSet<Attendence>();
}
public int St_id { get; set; }
public string St_name { get; set; }
public string St_guardian_name { get; set; }
public string St_guardian_relation { get; set; }
public string St_guardian_contact { get; set; }
public string St_address { get; set; }
public System.DateTime St_dob { get; set; }
public Nullable<int> St_cl_fk_id { get; set; }
public int St_status { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Attendence> Attendences { get; set; }
public virtual Class Class { get; set; }
}
Here is my Create Action in the StudentsController. PopulateClassDropDown is a helper method.
private void PopulateClassDropDownList(object selectedClass = null)
{
var classQuery = from c in db.Classes
where c.Cl_status==1
select c;
ViewBag.classID = new SelectList(classQuery, "Cl_id", "Cl_name", selectedClass);
}
[Authorize]
// GET: Students/Create
public ActionResult Create()
{
PopulateClassDropDownList();
return View();
}
// POST: Students/Create
// 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.
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "St_id,St_name,St_guardian_name,St_guardian_relation,St_guardian_contact,St_address,St_dob,St_cl_fk_id.St_status")] Student student)
{
try
{
var temp = student.St_cl_fk_id;
if (ModelState.IsValid)
{
student.St_status = 1;
db.Students.Add(student);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (RetryLimitExceededException /* dex*/ )
{
//Log the error (uncomment dex variable name 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.");
}
PopulateClassDropDownList(student.St_cl_fk_id);
return View(student);
}
And finally here is the Create View of Student.
#model GMASchoolProject.Models.Student
#{
ViewBag.Title = "Create";
}
<link rel="stylesheet" type="text/css" href="~/Content/Site.css">
<div class="row" style="margin-bottom:5px;">
<div class="col-lg-12">
<h1 class="page-header">Create New Student</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="row">
<div class="col-lg-8 col-lg-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
Fill in Details
</div>
<div class="panel-body">
<div class="row">
<form class="col-lg-6" role="form">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_name, "Student Name", htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.St_name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_guardian_name, "Name of Guardian", htmlAttributes: new { #class = "control-label " })
<div>
#Html.EditorFor(model => model.St_guardian_name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_guardian_name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_guardian_relation, "Guardian's Relation", htmlAttributes: new { #class = "control-label" })
<div>
#Html.DropDownListFor(model => model.St_guardian_relation, new[] {
new SelectListItem() {Text="Parents", Value="Parents" },
new SelectListItem() {Text="Other", Value="Other" }
},"Choose an option", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.St_guardian_relation, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_guardian_contact, "Guardian's Contact", htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.St_guardian_contact, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_guardian_contact, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_address, "Student's Address", htmlAttributes: new { #class = "control-label" })
<div>
#Html.TextAreaFor(model=>model.St_address, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_address, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
#Html.LabelFor(model => model.St_dob, "Student's Date of Birth", htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.St_dob, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.St_dob, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px;">
<label class="control-label col-md-2" for="ClassID">Class</label>
<div>
#Html.DropDownList("classID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.St_cl_fk_id, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" style="margin:15px,0,15px,0;">
<div class="col-md-offset-5 col-md-2">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn btn-danger" })
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Based on this, make these changes:
// classId implies a scalar value, this should be a list
ViewBag.classList = new SelectList(classQuery, "Cl_id", "Cl_name", selectedClass);
// Change your dropdown code:
#Html.DropDownList("St_cl_fk_id", (SelectList)ViewBag.classList, htmlAttributes: new { #class = "form-control" })
// or better yet:
#Html.DropDownListFor(m => m.St_cl_fk_id, (SelectList)ViewBag.classList, new { #class = "form-control" })
// remove this line - it should bind automatically
var temp = student.St_cl_fk_id;
I have PROPERTY VM which contains List<FounderInvestmentViewModel>.I have successfully inserted the partial view of FounderInvestmentViewModel into the Main Create Property view.
FounderInvestmentViewModel in turn contains List<InstallmentDetailsViewModel>. I have created the Partial View for InstallmentDetailsViewModel as _InstallmentDetails.cshtml and all the necessary actions.
I want to insert the _InstallmentDetails.cshtml into the partial view of FounderInvestmentViewModel which is in turn inserted into the Main View.
First let us take a look at the codes that I have used so far :--
Property View Model:-
public class PropertyViewModel
{
public int? Id { get; set; }
public string PropertyTitle { get; set; }
....other attributes....
public List<FounderInvestmentViewModel> FounderInvestments { get; set; } = new List<FounderInvestmentViewModel>();
}
FounderInvestmentViewModel:-
public class FounderInvestmentViewModel
{
public int? Id { get; set; }
public int InvestorId { get; set; }
public double Investment { get; set; }
public int InstallmentPeriod { get; set; }
public IEnumerable<SelectListItem> FounderInvestorList { get; set; }
public List<InstallmentDetailsViewModel> InstallmentDetails { get; set; } = new List<InstallmentDetailsViewModel>();
}
InstallmentDetailsViewModel:-
public class InstallmentDetailsViewModel
{
public int? Id { get; set; }
[Display(Name = "Pay Date")]
public List<DateTime> PayDates { get; set; }
[Required]
public List<double> InstallmentAmounts { get; set; }
}
PartialView for InstallmentDetails (_InstallmentDetails.cshtml):-
#model propertyMgmt.ViewModel.InstallmentDetailsViewModel
<div class="installmentDetails">
#using (Html.BeginCollectionItem("InstallmentDetails"))
{
#Html.HiddenFor(m => m.Id, new { #class = "id" })
<div class="form-group">
#Html.LabelFor(m => m.InstallmentAmounts, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(m => m.InstallmentAmounts, new { htmlAttributes = new { #class = "form-control", #type = "number" } })
#Html.ValidationMessageFor(m => m.InstallmentAmounts, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.PayDates, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(m => m.PayDates, new { htmlAttributes = new { #class = "form-control", #placeholder = "01/02/2017" } })
#Html.ValidationMessageFor(m => m.PayDates, "", new { #class = "text-danger" })
</div>
</div>
}
</div>
This _InstallmentDetails.cshtml is inserted into this _FounderInvestmentDetails.cshtml which is PartialView for FounderInvestmentDetails View Model:-
#model propertyMgmt.ViewModel.FounderInvestmentViewModel
<div class="founderInvestmentDetails">
#using (Html.BeginCollectionItem("FounderInvestments"))
{
#Html.HiddenFor(m => m.Id, new { #class = "id" })
<div class="form-group">
#Html.LabelFor(m => m.InvestorId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.InvestorId, Model.FounderInvestorList, "Select Investor", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.InvestorId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Investment, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(m => m.Investment, new { htmlAttributes = new { #class = "form-control", #type = "number" } })
#Html.ValidationMessageFor(m => m.Investment, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.InstallmentPeriod, htmlAttributes: new { #class = "control-label col-md-2", #type = "number" })
<div class="col-md-10">
#Html.EditorFor(m => m.InstallmentPeriod, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(m => m.InstallmentPeriod, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" id="installmentDetailsDiv">
#foreach (var InstallmentDetails in Model.InstallmentDetails)
{
#Html.Partial("_InstallmentDetails", InstallmentDetails)
}
</div>
<div class="form-group col-md-10">
<input type="button" class="btn btn-info btn-xs" value="Add Installment Details" onclick="addInstallmentDetails()" />
</div>
}
</div>
This is the MAIN CREATE VIEW :-
#model propertyMgmt.ViewModel.PropertyViewModel.PropertyViewModel
#{
ViewBag.Title = "Create";
}
<script src="~/Areas/Admin/themes/jquery/jquery.min.js"></script>
<h2>Property</h2>
#using (Html.BeginForm("Create", "Property", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Add Property</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.PropertyTitle, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PropertyTitle, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PropertyTitle, "", new { #class = "text-danger" })
</div>
</div>
.....Other form Groups.....
<div id="founderInvestmentDetails">
#foreach(var FounderInvestments in Model.FounderInvestments)
{
#Html.Partial("_FounderInvestmentDetails", FounderInvestments)
}
</div>
<div class="form-group col-md-10" >
<input type="button" class="btn btn-info btn-xs" value="Add Founder Investors" onclick="addFounderInvestors()" />
</div>
</div>
}
This is My JS Code in the Main View:-
function addFounderInvestors() {
var url = '#Url.Action("FounderInvestmentDetails")';
var form = $('form');
var founders = $('#founderInvestmentDetails');
$.get(url, function (response) {
founders.append(response);
// Reparse the validator for client side validation
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
};
function addInstallmentDetails() {
var url = '#Url.Action("InstallmentDetails")';
var form = $('form');
var installments = $('#installmentDetailsDiv');
$.get(url, function (response) {
installments.append(response);
// Reparse the validator for client side validation
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
};
Controller Code :-
public PartialViewResult FounderInvestmentDetails()
{
var model = new FounderInvestmentViewModel {
FounderInvestorList = _investorQueryProcessor.GetInvestorByType(1).Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.InvestorName
})
};
//return PartialView(model);
return PartialView("_FounderInvestmentDetails", model);
}
public PartialViewResult InstallmentDetails()
{
return PartialView("_InstallmentDetails",new InstallmentDetailsViewModel());
}
public ActionResult Create()
{
if (Session["AdminName"] != null)
{
//ViewBag.Investors = SelectListItems;
List<FounderInvestmentViewModel> model = new List<FounderInvestmentViewModel>();
List<InstallmentDetailsViewModel> model2 = new List<InstallmentDetailsViewModel>();
return View(new PropertyViewModel());
}
else return Redirect("/Account/Login");
}
EDIT:-
Sorry this is what is throwing the exception -->> Collection.cshtml
PROCESS:- In the Main View, "Add Founder Investor Buttons" on click event adds the partial view _FounderInvestmentDetails.cshtml successfully.Now the "Add Installment Details" button is appended.Upon clicking this "Add Installment Details" button _InstallmentDetails.cshtml partial view should be appended,BUT this part is not working. When I click this button, I get the error "Object reference not set to an instance of an object" in the following code:-
#using HtmlHelpers.BeginCollectionItem
<ul>
#foreach (object item in Model)-->>ERROR CODE
{
<li>
#using (Html.BeginCollectionItem(Html.ViewData.TemplateInfo.HtmlFieldPrefix))
{
#Html.EditorFor(_ => item, null, "")
}
</li>
}
</ul>
The Paydates and Installments does not need to be <List> as it already is a PartialView and can be added multiple times.
public class InstallmentDetailsViewModel {
public int? Id { get; set; }
[Display(Name = "Pay Date")]
public List<DateTime> PayDates { get; set; }
[Required]
public List<double> InstallmentAmounts { get; set; }
}
I need correction on the code below.
I have 2 classes "Employee" and "Child".
When I want to create a new Employee, I would like to be able to create in that same form the related Child (2 Children maximum).
Below are the models
public class Employee
{
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int ChildID { get; set; }
public virtual ICollection<Child> Childs { get; set; }
}
public class Child
{
public int ChildID { get; set; }
public string NameChild { get; set; }
public string SurnameChild { get; set; }
public virtual Employee Employee { get; set; }
}
The Employee controller
public class EmployeController : Controller
{
private ComideContext db = new ComideContext();
// GET: Employe/Create
public ActionResult Create()
{
List<Child> model = new List<Child>();
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "EmployeID,Name,Surname,ChildID")] Employee employee)
{
if (ModelState.IsValid)
{
db.Employes.Add(employe);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(employe);
}
}
The View of the Employee form
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Employe</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<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.Surname, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Surname, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Surname, "", new { #class = "text-danger" })
</div>
</div>
#for (int i=0; i<2; i++ )
{
<div class="form-group">
#Html.LabelFor(model => model.NameChild, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.NameChild, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.NameChild, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SurnameChild, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SurnameChild, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SurnameChild, "", 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>
}
Any help/thoughts would be most appreciated.
Thank you.
Disclaimer: I've done this on MVC 3. I don't know if there is an easier way to do it in MVC 5.
You will need to index the children in the view code so when you submit the form the model binder knows how to construct the Employee object.
This could be done this way:
for (var i = 0 ; i < collectionSize; i++)
{
#Html.EditorFor(child => Model.Childs[i].ChildID)
#Html.ValidationMessageFor(child => Model.Childs[i].ChildID)
[....]
}
This would require your collection to be initialized when passed to the view.
Another way you can bind to collection is to programatically build the html components' name to include their index in the list.
See the example below:
<input name="Employee.Childs[0].ChildID" >
<input name="Employee.Childs[1].ChildID" >
So here is some code:
Controller
[HttpGet]
public ActionResult GetSettings()
{
var save = new SettingsSaver();
var dto = save.GetSettings();
var model = new SettingsModel
{
Password = dto.Password,
Port = dto.Port,
Username = dto.Username,
Enabled = dto.Enabled,
Id = dto.Id,
IpAddress = dto.IpAddress,
};
return View(model);
}
[HttpPost]
public ActionResult GetSettings(SettingsModel viewModel)
{
if (ModelState.IsValid)
{
var dto = new SettingsDto
{
IpAddress = viewModel.IpAddress,
Password = viewModel.Password,
Port = viewModel.Port,
Username = viewModel.Username,
Enabled = viewModel.Enabled,
Id = viewModel.Id
};
var save = new SettingsSaver();
var result = save.SaveSettings(dto); //Saves correctly and updates in DB
if (result)
{
return View(); // Returns this
}
return View("Error");
}
return View("Error");
}
View (Default Edit View)
#model Dash.UI.Models.Settings.SettingsModel
#{
ViewBag.Title = "Settings";
}
<h2>Settings</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Settings</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.Enabled, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.Enabled)
#Html.ValidationMessageFor(model => model.Enabled, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.IpAddress, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.IpAddress, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.IpAddress, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Port, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Port, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Port, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Username, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Username, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Username, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Password, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Password, "", new { #class = "text-danger" })
</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>
So, what the problem is when I update the model and POST to GetSettings it all works correctly, updates in the db etc. but on the return View() it does not hit the GetSettings() action method, but it returns the view with all of the model filled in except the password.
Model
public class SettingsModel : BaseSettingsViewModel // Base contains ID and Enabled properties with no data annotations
{
[Required]
[DataType(DataType.Text)]
[DisplayName("IP Address")]
public string IpAddress { get; set; }
[Required]
[DisplayName("Port")]
public int Port { get; set; }
[Required]
[DataType(DataType.Text)]
[DisplayName("Username")]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
[DisplayName("Password")]
public string Password { get; set; }
}
Any advise/guidance would be much appreciated.
Upon returning the same view from a POST, the ModelState will fill in the controls (apart from the password fields) from the posted values.
So you need a Post-Redirect-Get pattern:
if (result)
{
return RedirectToAction("GetSettings");
}
I have this ViewModel:
public class Rapport
{
[Key]
public int RapportId { get; set; }
public RapportAnomalie rapport { get; set; }
public IEnumerable<RefAnomalie> refAnomalies { get; set; }
}
which has two models in it, RapportAnomalie :
public class RapportAnomalie
{
[Key]
public int codeRapport { get; set; }
public DateTime date { get; set; }
public String heure { get; set; }
public String etat { get; set; }
[ForeignKey("codeAgence")]
public virtual Agence agence { get; set; }
public int codeAgence { get; set; }
public IEnumerable<LigneRapportAnomalie> lignesRapport { get; set; }
}
and RefAnomalie.
However when I want to send data from view to controller from a form, I keep getting an exception.
The view :
#model InspectionBanque.Models.Rapport
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>RapportAnomalie</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.rapport.date, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.rapport.date, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.rapport.heure, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.rapport.heure, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.rapport.etat, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.rapport.etat, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.rapport.codeAgence, "codeAgence", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("codeAgence", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.rapport.codeAgence, "", 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>
}
#for (int i = 0; i < Model.refAnomalies.Count(); i++)
{
<div class="col-md-10">
#Html.DisplayFor(model => model.refAnomalies.ElementAt(i).libele)
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
and then the controller :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create( Rapport rapportAnomalie)
{
if (ModelState.IsValid)
{
RapportAnomalie rp = new RapportAnomalie();
db.rapportAnomalies.Add(rapportAnomalie.rapport);
db.SaveChanges();
return RedirectToAction("Index");
}
var refanomal = from r in db.refAnnomalies
select r;
Rapport rapport = new Rapport { rapport = rapportAnomalie.rapport, refAnomalies = refanomal.ToArray() };
ViewBag.codeAgence = new SelectList(db.Agences, "codeAgence", "intituleAgence", rapportAnomalie.rapport.codeAgence);
return View(rapport);
}
Any ideas what's wrong with it?
I think you are getting the problem because the lignesRapport field is not initialized in your model RapportAnomalie
Create a constructor and initialize lignesRapport . I believe the problem will go away.
public RapportAnomalie()
{
lignesRapport = new List <LigneRapportAnomalie>();
}
Good luck