I am trying to bind all my model data at once through a form submission in MVC 5 using an edited version of BeginCollectionItem as discussed in Joe Steven's blog here.
The model, Company
, has a List<Pa_Ipv4>
, the class Pa_Ipv4
in turn has a List<IpAllocation>
, I want to access and save to the database all the properties of the IpAllocation
in each Pa_Ipv4
.
IE: Model.pa_ipv4s[x].requestedIps[x].subnet
The main page is using model Company
, which has a partial accepting Pa_Ipv4
, which has a partial accepting IpAllocation
.
Question 1: In my controller, I'm setting a string property for the first item in the list (requestedIp), but when I submit and postback, the property (allocationType
) is null, this property needs to be hard coded as it's for internal use within the DB - why is this being reset?
Reason: The property isn't in the post method, as such what is initially declared is discarded as it's not within the end post.
Possible Solution: Use a hidden property within the form so that it is present when the form is posted and the user cannot access the property.
Question 2: BeginCollectionItem is naming attributes appropriately, IE: pa_ipv4s[8e075d50-a5fb-436f-9cef-85abfb6910e3].requestedIps[b693b83c-b6b1-4c42-b983-4d058e766d4c].subnet
, but only the initial model, it's then ignoring any others created, what have I done wrong?
Reason: The GUID needed for a prefix generated by the Pa_Ipv4 sections BeginCollectionItem is not able to be accessed by the IpAllocation BeginCollectionItem, as such only the initial content has the correct prefixes, anything added hereafter misses the necessary prefix.
Another potential solution is essentially the same concept, but instead of using a div, use html data attribute instead so that it's accessible.
I think both of the issues I'm experiencing are to do with how I've set my controller up, but I've included the Views and Model below as well. The model contains all the properties, lots of these have been removed in my views to save space as these are not causing the issue.
Create
@model Company
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm())
{
<div class="jumboservice">
<div data-role="page">
<div data-role="header">
<h2>PA IPv4 Request Form</h2>
</div>
<div class="ui-content" data-role="main">
<h3>Company Details</h3>
<div class="ui-grid-c ui-responsive">
<div class="ui-block-a">
<p class="lblStyle">Company Name</p>
<span>
@Html.EditorFor(m => m.name)
@Html.ValidationMessageFor(m => m.name)
</span>
</div>
</div>
</div>
<br />
@foreach (var i in Model.pa_ipv4s)
{
@Html.Partial("Pa_IPv4View", i)
}
<br />
<div data-role="main" class="ui-content">
<div data-role="controlgroup" data-type="horizontal">
<input type="submit" class="ui-btn" value="Create" />
</div>
</div>
</div>
</div>
}
<script type="text/javascript">
$(function () {
$('#addItemRIpM').on('click', function () {
$.ajax({
url: '@Url.Action("RequestedManager")',
cache: false,
success: function (html) { $("#editorRowsRIpM").append(html); }
});
return false;
});
$('#editorRowsRIpM').on('click', '.deleteRow', function () {
$(this).closest('.editorRow').remove();
});
});
</script>
Pa_Ipv4 Partial
@model Pa_Ipv4
@using (HtmlHelpers.BeginCollectionItem.HtmlPrefixScopeExtensions.BeginCollectionItem(Html,"pa_ipv4s"))
{
@Html.AntiForgeryToken()
<div class="ui-grid-c ui-responsive">
<div class="ui-block-a">
<p class="lblStyle">Subnet</p>
</div>
<div class="ui-block-b">
<p class="lblStyle">Size(CIDR)</p>
</div>
<div class="ui-block-c">
<p class="lblStyle">Mask</p>
</div>
<div class="ui-block-d">
</div>
</div>
@*Request IP Address Space List*@
<div id="editorRowsRIpM">
@foreach (var item in Model.requestedIps)
{
@Html.Partial("RequestedIpView", item)
}
</div>
@Html.ActionLink("Add", "RequestedManager", null, new { id = "addItemRIpM", @class = "button" })
}
RequestedIp Partial
@model IpAllocation
<div class="editorRow">
@using (HtmlHelpers.BeginCollectionItem.HtmlPrefixScopeExtensions.BeginCollectionItem(Html, "requestedIps"))
{
<div class="ui-grid-c ui-responsive">
<div class="ui-block-a">
<span>
@Html.TextBoxFor(m => m.subnet)
</span>
</div>
<div class="ui-block-b">
<span>
@Html.TextBoxFor(m => m.cidr)
</span>
</div>
<div class="ui-block-c">
<span>
@Html.TextBoxFor(m => m.mask)
<span class="dltBtn">
<a href="#" class="deleteRow">Remove</a>
</span>
</span>
</div>
</div>
}
</div>
Controller
public ActionResult Create()
{
var cmp = new Company();
cmp.contacts = new List<Contact>
{
new Contact { email = "", name = "", telephone = "" }
};
cmp.pa_ipv4s = new List<Pa_Ipv4>
{
new Pa_Ipv4
{
ipType = "Pa_IPv4", registedAddress = false, existingNotes = "",
numberOfAddresses = 0, returnedAddressSpace = false, additionalInformation = "",
requestedIps = new List<IpAllocation>
{
new IpAllocation { allocationType = "Requested", cidr = "", mask = "", subnet = "" } // allocationType is null in cmp in the Create[HttpPost]
}
}
};
return View(cmp);
}
public ActionResult Pa_IPv4Manager()
{
return PartialView("Pa_IPv4View", new Pa_Ipv4());
}
public ActionResult RequestedManager()
{
return PartialView("RequestedIpView", new IpAllocation { allocationType = "Requested" }); // allocationType is null in cmp in the Create[HttpPost]
}
// POST: Pa_Ipv4/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Company cmp) //only one requestedIps count regardless of how many add
{
if (ModelState.IsValid)
{
db.companys.Add(cmp);
db.SaveChanges();
return RedirectToAction("Index");
}
Model
[Table("Ipv_Base")]
public class Ipv_Base
{
[Key]
public int ipv_baseId { get; set; }
public int companyId { get; set; }
[ForeignKey("companyId")]
public Company company { get; set; }
public string ipType { get; set; }
[Required]
public bool registedAddress { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string existingNotes { get; set; }
[Required]
public int numberOfAddresses { get; set; }
[Required]
public bool returnedAddressSpace { get; set; }
[DataType(DataType.MultilineText)]
public string additionalInformation { get; set; }
// navigation properties
public virtual IList<IpAllocation> requestedIps { get; set; }
}
[Table("Company")]
public class Company
{
[Key]
public int companyId { get; set; }
[Required]
public string name { get; set; }
[Required]
public string telephone { get; set; }
[Required]
public string regNumber { get; set; }
// navigation properties to keep track of the models that belong to the company
public virtual IList<Pa_Ipv4> pa_ipv4s { get; set; }
}
[Table("IpAllocation")]
public class IpAllocation
{
[Key]
public int ipAllocationId { get; set; }
public int ipv_BaseId { get; set; }
[ForeignKey("ipv_BaseId")]
public Ipv_Base ipv_Base { get; set; }
[Required]
public string allocationType { get; set; }
[Required]
public string subnet { get; set; }
[Required]
public string cidr { get; set; }
[Required]
public string mask { get; set; }
}
public class Pa_Ipv4 : Ipv_Base
{
public Pa_Ipv4()
{
ipType = "pa_ipv4";
}
}
See Question&Answers more detail:
os