Want to add multiple textbox in mvc4 regor - asp.net-mvc-4

I have two Model Class
public partial class EndUser
{
public EndUser()
{
this.Mobiles = new List<Mobile>();
}
public virtual long Id { get; set; }
public virtual string FullName { get; set; }
[DataType(DataType.Password)]
public virtual string UserPassword { get; set; }
public virtual string Email { get; set; }
public virtual IList<Mobile> Mobiles { get; set; }
public partial class Mobile
{
public virtual long Id { get; set; }
public virtual string Number { get; set; }
public virtual EndUser EndUser { get; set; }
}
My controller
public ActionResult CreateClient()
{
return View("CreateClient");
}
Scaffold Template Create My view
CreateClient
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>EndUser</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FullName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FullName)
#Html.ValidationMessageFor(model => model.FullName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.UserPassword)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserPassword)
#Html.ValidationMessageFor(model => model.UserPassword)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
But I want to add my Client Mobile From this view. How can i create multiply(unknown) text field to add mobile numbers? If client have more then one mobile number he can add more textbox by clicking "Add More Number" button. I cant create textbox for mobile number field.
Please help me out. Im new in MVC.

It's not as easy as you think...
Check this for a quick info. Check this for a complete how-to

You can resume it in a few steps.
Create a view (ie) "DynamicMobileForm" where you will have a foreach Model.Mobiles, it should create a textbox for each item.
In the controller, create a Get method to retrieve only this partial DynamicMobileForm view (You can use the same model, should contain at least your Mobiles property loaded)
In your ABM form, remove any html regarding mobile, and paste this:
#{Html.RenderPartial("DynamicMobileForm", Model);} this will render this section only.
Now you just need a way to dynamically increment the amount of editors, this is very easy, create a button, and with jquery perform a call to controller with a POST Method, like DynamicMobileFormAddRow... Inside this method, you only need to Add() a new instance inside your Model.Mobiles list, and return the same model as your GetMethod.
When the page loads, will render your partial section only, adding a new textbox, and when you submit it, will automatically post it inside your Mobiles Array.
Hope it helps.

Related

Complex models and data binding ASP.NET Core 5 issue

I am using ASP.NET Core 5 with a complex model and I am having a heck of a time getting the model to post correctly.
Here is my model class:
public class Project
{
[Key]
public int ProjectId { get; set; }
[Required]
public string Name { get; set; }
public virtual List<ResponsibleParty> ResponsibleParties { get; set; }
public virtual List<ProjectManager> ProjectManagers { get; set; }
}
In my razor page I am doing the following:
[BindProperty]
public Project Project { get; set; }
[BindProperty]
public ResponsibleParty ResponsibleParty { get; set; }
I am using a bootstrap model to popup a window that allows the user to enter the information for ResponibleParty and an "Add" button that posts back where I add the ResponsibleParty to the Project.ResponsibleParty list. On the page returns I can see the ResponsibleParty was added and displayed.
Now.. when I try to add another and the page posts the project model no longer contains the ResponsibleParty.
Any ideas here on what I'm doing wrong?
I am using a bootstrap model to popup a window that allows the user to
enter the information for ResponibleParty and an Add button that posts
back where I add the ResponsibleParty to the Project.ResponsibleParty
List. One the page returns I can see the ResponsibleParty was added
and displayed. Now.. When I try to add another and the Page Posts the
Project model no longer contains the ResponsibleParty. Any Ideas here
on what I'm doing wrong?
Please check your Post method, whether the new item is inserted successfully, and in the get method, whether you are getting the latest data.
Based on the model and your description, I create a sample and use session to store the Project data, you can refer to them:
Configure the application to use session, and add the SessionExtensions class to store object. Refer this article: Configure session state
[Note] Please note the session expired time. Besides, if you don't want to use the session, you can also store the data into database.
Create model:
public class Project
{
[Key]
public int ProjectId { get; set; }
[Required]
public string Name { get; set; }
public virtual List<ResponsibleParty> ResponsibleParties { get; set; }
public virtual List<ProjectManager> ProjectManagers { get; set; }
}
public class ResponsibleParty
{
public int ResponsiblePartyId { get; set; }
public string Name { get; set; }
}
public class ProjectManager {
public int PMid { get; set; }
public string PMName { get; set; }
}
Create a ProjectIndex Razor Page:
ProjectIndex.cshtml:
#page "/projectIndex"
#model RazorWebApplication.Pages.ProjectIndexModel
#{
ViewData["Title"] = "Home page";
}
<h2>Project Index</h2>
<div class="container">
#if (Model.Project != null && Model.Project.ResponsibleParties.Count > 0)
{
<table class="table">
<thead>
<tr>
<th>
ProjectId
</th>
<th>
Name
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Project.ResponsibleParties)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ResponsiblePartyId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.ResponsiblePartyId">Edit</a> |
<a asp-action="Details" asp-route-id="#item.ResponsiblePartyId">Details</a> |
<a asp-action="Delete" asp-route-id="#item.ResponsiblePartyId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
}
</div>
<!-- Button to Open the Modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">
Create New ResponsibleParty
</button>
<!-- The Modal -->
<div class="modal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<form method="post" asp-page-handler="AddResponsibleParty">
<div class="container-fluid">
<div class="row p-5 border pt-4 my-3 rounded">
<div class="input-group row mb-3">
<div class="col-md-4 col-sm-12 d-sm-block">
<label asp-for="ResponsibleParty.ResponsiblePartyId"></label>
</div>
<div class="col-md-8 col-sm-12">
<textarea class="form-control" asp-for="ResponsibleParty.ResponsiblePartyId"></textarea>
<span class="text-danger" asp-validation-for="ResponsibleParty.ResponsiblePartyId"></span>
</div>
</div>
<div class="input-group row mb-3">
<div class="col-md-4 col-sm-12 d-sm-block">
<label asp-for="ResponsibleParty.Name"></label>
</div>
<div class="col-md-8 col-sm-12">
<textarea class="form-control" asp-for="ResponsibleParty.Name"></textarea>
<span class="text-danger" asp-validation-for="ResponsibleParty.Name"></span>
</div>
</div>
<div class="input-group row mb-3">
<input type="submit" value="Submit" />
</div>
</div>
</div>
</form>
</div>
</div>
</div>
ProjectIndex.cshtml.cs:
public class ProjectIndexModel : PageModel
{
[BindProperty]
public Project Project { get; set; }
[BindProperty]
public ResponsibleParty ResponsibleParty { get; set; }
private readonly string sessionkeyproject = "project";
public void OnGet()
{
//check if the seesion is null.
if (HttpContext.Session.Get<Project>(sessionkeyproject) == default)
{
//if session is null, set the initial data.
Project = new Project()
{
ProjectId = 101,
Name = "A",
ResponsibleParties = new List<ResponsibleParty>()
{
new ResponsibleParty(){ ResponsiblePartyId=1001, Name="RP1"},
new ResponsibleParty(){ ResponsiblePartyId=1002, Name="RP2"},
}
};
//store the data using session
HttpContext.Session.Set<Project>(sessionkeyproject, Project);
}
else
{
// get the latest data from the session.
Project = HttpContext.Session.Get<Project>(sessionkeyproject);
}
}
public async Task<IActionResult> OnPostAddResponsibleParty()
{
var newitem = ResponsibleParty;
if (HttpContext.Session.Get<Project>(sessionkeyproject) == default)
{
return RedirectToPage();
}
else
{
//get the project from the session
Project = HttpContext.Session.Get<Project>(sessionkeyproject);
}
//add the new responsibleparty into the project
Project.ResponsibleParties.Add(new ResponsibleParty()
{
ResponsiblePartyId = newitem.ResponsiblePartyId,
Name = newitem.Name
});
//update the seesion to store the latest data.
HttpContext.Session.Set<Project>(sessionkeyproject, Project);
return RedirectToPage();//still to decide where it should go
}
}
The result as below:

Can I edit multiple models in ASP.NET MVC using Partial Views?

I'm new to ASP.NET MVC 4 and I'm struggling with a concept that would be easy in webforms. So, if I have a Customer class, and a Customer has an Address, how can I edit both the Customer and Address on the same form in the same submit action? I would like to create an '_Edit' partial view for the Address, but I don't know how to wire the controller up if there is no submit button for the Address. I just want a single button to save all the Models in a single View.
So, I could create a new CompanyView model, view, and controller and do it that way. However, if I have many objects having Addresses it seems like a lot of work to keep creating View Models to allow you to edit both the object and the address in the same form. Is there a way to create an Address partial edit view and somehow update the Address fields in the Company Edit Controller? Or, have it somehow pass the model.Address back to the Company Edit Controller instead of null?
Edit:
Models
public class Address
{
public Int32 Id { get; set; }
[Display(Name = "Address 1")]
public String Address1 { get; set; }
[Display(Name = "Address 2")]
public String Address2 { get; set; }
[Display(Name = "City")]
public String City { get; set; }
[Display(Name = "State")]
public String State { get; set; }
[Display(Name = "Postal Code")]
public String PostalCode { get; set; }
[Display(Name = "Country")]
public String Country { get; set; }
}
public class Company
{
public Int32 Id { get; set; }
[Display(Name = "Company Name")]
public String Name { get; set; }
public Int32 AddressId { get; set; }
public virtual Address Address { get; set; }
}
Address _Edit Partial View
#model Models.Address
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.EditorFor(model => model.Address1)
#Html.EditorFor(model => model.Address2)
#Html.EditorFor(model => model.City)
#Html.EditorFor(model => model.State)
#Html.EditorFor(model => model.PostalCode)
#Html.EditorFor(model => model.Country)
</fieldset>
</div>
Company Edit View
#model Models.Company
#{
ViewBag.Title = "Edit";
Layout = "~/Views/shared/ContentLayout.cshtml";
}
<div class="row">
<div class="col-lg-12">
<div class="page-header">
<h2>Edit Company</h2>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
#using (Html.BeginForm("Edit", "Company", new { #class = "bs-example form-horizontal" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.EditorFor(model => model.Name)
#Html.HiddenFor(model => model.AddressId)
#Html.Partial("~/Views/Address/_Edit.cshtml", Model.Address)
<p>
<button name="button" type="submit" class="btn btn-primary" value="submit">Submit</button>
</p>
}
</div>
</div>
Company Edit Controller
[HttpPost]
public ActionResult Edit(Company model, int id)
{
if (ModelState.IsValid)
{
// model.Address = NULL here!
Success("Record updated!");
return RedirectToAction("Index");
}
}
For model binding to work properly, you need to post only a Company back to your controller. Just pass your whole model onto your partial :
#model Models.Company
#{
ViewBag.Title = "Edit";
Layout = "~/Views/shared/ContentLayout.cshtml";
}
<div class="row">
<div class="col-lg-12">
<div class="page-header">
<h2>Edit Company</h2>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
#using (Html.BeginForm("Edit", "Company", new { #class = "bs-example form-horizontal" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.EditorFor(model => model.Name)
#Html.HiddenFor(model => model.AddressId)
#Html.Partial("~/Views/Address/_Edit.cshtml", Model)
<p>
<button name="button" type="submit" class="btn btn-primary" value="submit">Submit</button>
</p>
}
</div>
</div>
_Edit
#model Models.Company
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.HiddenFor(model => model.Address.Id)
#Html.EditorFor(model => model.Address.Address1)
#Html.EditorFor(model => model.Address.Address2)
#Html.EditorFor(model => model.Address.City)
#Html.EditorFor(model => model.Address.State)
#Html.EditorFor(model => model.Address.PostalCode)
#Html.EditorFor(model => model.Address.Country)
</fieldset>
</div>
Controller
[HttpPost]
public ActionResult Edit(Company model, int id)
{
if (ModelState.IsValid)
{
// model.Address should now be available
Success("Record updated!");
return RedirectToAction("Index");
}
}
You should now see the Address navigation property of your model properly bound on post.
Edit based on question in comment
How you set up your views and partials is up to you really. The important thing to remember is that model binding works based on the names given to the form elements by the HTML helpers.
So Html.HiddenFor(m => m.Id) will result in <input name="Id"> while Html.HiddenFor(m => m.Address.Id) will result in <input name="Address.Id">. First one won't be picked up by the model binder as a navigation property of Company, second one will.
The simple route would be to just duplicate your partial view. But if it gets to the point where your partial becomes quite large and complex with a high amount of fields, you could create a partial base class that both your entities inherit of.
BaseEntityWithAddress.cs
public partial class BaseEntityWithAddress
{
public virtual Address Address { get; set; }
}
Customer.cs
public class Customer : BaseEntityWithAddress
{
// your properties, no need to redefine Address here
}
Vendor.cs
public class Vendor: BaseEntityWithAddress
{
// your properties, no need to redefine Address here
}
And then your partial view would take BaseEntityWithAddress as a model to which you would still pass the whole model.
_Edit.cshtml
#model Models.BaseEntityWithAddress
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.HiddenFor(model => model.Address.Id)
#Html.EditorFor(model => model.Address.Address1)
#Html.EditorFor(model => model.Address.Address2)
#Html.EditorFor(model => model.Address.City)
#Html.EditorFor(model => model.Address.State)
#Html.EditorFor(model => model.Address.PostalCode)
#Html.EditorFor(model => model.Address.Country)
</fieldset>
</div>
And that will generate form elements with the correct names for the model binder to pick up.
So you would have 2 classes:
class Address
{
public string street {get;set;}
public string state {get;set;}
}
class Customer
{
public string name {get;set;}
public Address address {get;set;} // links to the above class.
}
your main customer view would be something like:
#model Models.Customer
#using (Html.BeginForm()
{
#Html.TextBoxFor(m => m.name)
#Html.Partial("_Edit", Model.address)
<button type="submit">Submit</button>
}
your partial:
#model Models.Address
#Html.TextBoxFor(m => m.street)
#Html.TextBoxFor(m => m.state)
then in your controller:
public ActionResult customer(Customer model)
{
// do whatever
}

Login form still posting even though required input is empty

I'm using jquery unobtrusive validation in a new MVC4 solution. My problem is that on my login page when I click the submit button the page is still posted even though my required fields are empty.
I have another page where I have the same setup and that one doesn't post.
This is my login page:
<div id="loginForm">
#Html.SiteLogo()
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div id="loginForm-container" class="spacer-below">
<fieldset>
<legend>Log in Form</legend>
<div class="input-control text" data-role="input-control">
#Html.TextBoxFor(m => m.UserName, new { placeholder="Please enter your username"})
#Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="input-control password" data-role="input-control">
#Html.PasswordFor(m => m.Password, new { placeholder="Please enter your password"})
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="input-control checkbox" data-role="input-control">
<label>
#Html.CheckBoxFor(m => m.RememberMe)
<span class="check"></span> Remember me
</label>
</div>
<div class="input-control">
<input type="submit" class="primary small" value="Log in" />
</div>
</fieldset>
</div>
<div class="forgotPassword">#Html.ActionLink("Forgotten password?", "ForgotPassword")</div>
<span>#Html.Partial("_CustomerSupport")</span>
}
</div>
And the viewmodel for this page:
public class LoginModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me")]
public bool RememberMe { get; set; }
}
And this the HTMl for a page that does work i.e. does not post if the input is empty
<div id="resetPasswordForm">
#Html.SiteLogo()
<h4>Reset Password</h4>
#using (Html.BeginForm(new {ReturnUrl = ViewBag.ReturnUrl}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(vm => vm.Authentication.Token)
#Html.ValidationMessageFor(vm => vm.Authentication.Token)
<div id="resetPasswordForm-container" class="spacer-below">
<fieldset>
<legend>Reset password form</legend>
<div class="input-control text" data-role="input-control">
#Html.TextBoxFor(vm => vm.Authentication.EmailAddress, new { placeholder="Please enter your email address"})
#Html.ValidationMessageFor(vm => vm.Authentication.EmailAddress)
</div>
<div class="input-control password" data-role="input-control">
#Html.PasswordFor(vm => vm.NewPassword, new { placeholder="Please enter a new password"})
#Html.ValidationMessageFor(vm => vm.NewPassword)
</div>
<div class="input-control text" data-role="input-control">
#Html.PasswordFor(vm => vm.ConfirmPassword, new { placeholder="Please enter the password again"})
#Html.ValidationMessageFor(vm => vm.ConfirmPassword)
</div>
<div class="input-control">
<input type="submit" class="primary medium" value="Reset Password" />
</div>
</fieldset>
</div>
<span>#Html.Partial("_CustomerSupport")</span>
}
</div>
And my viewmodel for this page:
public class ResetPasswordViewModel
{
public ResetPasswordViewModel()
{
Authentication = new ResetPasswordConfirmViewModel();
}
public ResetPasswordConfirmViewModel Authentication { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new passwords do not match, please enter again.")]
public string ConfirmPassword { get; set; }
}
My view references the appropriate scripts as checked when I view the source:
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
I should also mention that I'm following the guide from:
http://nickstips.wordpress.com/2011/08/18/asp-net-mvc-displaying-client-and-server-side-validation-using-qtip-tooltips/
In order to try and get hover like validation. This works perfectly except on the Login form. After further investigation it appears that the code is error'ing out in the onError() method change due to possibly there being no validation on this field (I do not require validation on the remember me as it's optional).
var replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;
I'm guessing as my input is not required for validation it doesn't have the data-valmsg-replace attribute and hence this line is causing the javascript to fail and so the post goes through?
The problem appeared to be because of the Remember Me checkbox not having any validation attributes applied. When the code got into the onError() method it was failing on this line:
var replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;
as container.attr("data-valmsg-replace") was an empty string.
I replaced this code with:
var elementJson = container.attr("data-valmsg-replace") || 'false';
var replace = $.parseJSON(elementJson) !== false;
and it all seems to work ok now. I'm not sure if that is the best way to write the javascript but seems to do the trick.
The original code as mentioned in the question was from:
MVC clientside and serverside using qTip
Make sure your view references the scripts:
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
That might sound obvious, but for certain options on the create view dialog box, even if you have Reference script libraries checked, it won't actually add the scripts to the view, so it's worth double-checking.
Edit
Just noticed you're using MVC 4, in which case, this might be what you're missing at the bottom of your view:
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I was actually able to reproduce the problem of the validation not firing if the scripts aren't bundled.

MVC "create view" when there is one to many relationship in model

My model is simple, one client can have many phone numbers :
I have represented this in Entity Framework
Generated client class is as below.
public partial class Client
{
public Client()
{
this.PhoneNumbers = new HashSet<PhoneNumber>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
}
And now I need to create a view page for "create client". This page should have space to enter PhoneNumbers also (ex: By default there should be two text boxes to enter phone numbers)
<fieldset>
<legend>Client</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
as the above "create view" we can easily give an space for "model.Name", because it is a simple property. But how can i do something similar for collection of phone numbers..??
I know that we can achieve this with ugly javascript code, but I would like to know the best easy and simple way, that we can use with ASP.NET MVC ... ?
You have to do a few things:
First create a ViewModel that has the properties you need:
public class ClientViewModel
{
public int Id {get;set;}
public string Name {get;set;}
public PhoneNumber PhoneNumber1 {get;set;}
public PhoneNumber PhoneNumber2 {get;set;}
}
Change Create to return the ClientViewModel
[HttpGet]
public ActionResult Create()
{
return View(new ClientViewModel());
}
Map the HttpPost to use the ClientViewModel and map the values to it:
[HttpPost]
public ActionResult Create(ClientViewModel clientViewModel)
{
var client = new Client();
client.Name = clientViewModel.Name;
client.PhoneNumbers.Add(clientViewModel.PhoneNumber1);
client.PhoneNumbers.Add(clientViewModel.PhoneNumber2);
db.Clients.Add(client);
db.SaveChanges();
return RedirectToAction("Index", "Client");
}
Then, finally, modify your view:
<fieldset>
<legend>Client</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PhoneNumber1.Number)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumber1.Number)
#Html.ValidationMessageFor(model => model.PhoneNumber1.Number)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PhoneNumber2.Number)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumber2.Number)
#Html.ValidationMessageFor(model => model.PhoneNumber2.Number)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
For the collection you can use something like this:
#for(int i = 0; i < Model.PhoneNumbers.Count; i++)
{
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumbers[i])
#Html.ValidationMessageFor(model => model.PhoneNumbers[i])
</div>
}

.NET MVC 4 Strongly typed ViewModel containing Strongly typed Model with EditorFor and EditorTemplate partial view not binding

There has been a lot of questions about this... but somehow I can't get this binding to work and I'm still getting null values in my posted View Model. This is MVC 4.
Here is the Main View Model
public class RoleVM {
[Required]
[Display(Name = "Name of the Role")]
public string Role {get; set;}
public IEnumerable<RolePermission> permissions { get; set; }
}
Here is the RolePermission Class
public class RolePermission {
public int id;
public bool permission_value;
public string name { get; set; }
}
Here is GET Create Method in the controller
public ActionResult Create() {
RoleVM role_vm = new RoleVM();
var allpermissions = from p
in permission_repo.GetPermissions()
select p;
role_vm.permissions = from p
in allpermissions
select new RolePermission
{ name = p.name, id = p.PermissionId, permission_value = false };
return View(role_vm);
}
Here is the Create.cshtml file
#model RoleVM
#using (Html.BeginForm("Create", "Role",
FormMethod.Post, new { #class = "permission_form" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>RoleVM</legend>
<div class="form-item">
#Html.LabelFor(model => model.Role)
#Html.EditorFor(model => model.Role)
#Html.ValidationMessageFor(model => model.Role)
</div>
#Html.EditorFor(model => model.permissions)
<p>
<input class="submit-btn" type="submit" value="Create" />
</p>
</fieldset>
}
Next here is the rolepermissions.cshtml file located in ~/Views/Shared/EditorTemplates
#model RolePermission
<div class="form-item">
#Html.HiddenFor(modelItem => modelItem.id)
#Html.LabelFor(modelItem => modelItem.permission_value, Model.name)
#Html.CheckBoxFor(modelItem => modelItem.permission_value)
</div>
Here is an example of one of the html items that is rendered on page
<div class="form-item">
<input data-val="true" data-val-number="The field Int32 must be a number." data-val-required="The Int32 field is required." id="permissions_2__id" name="permissions[2].id" type="hidden" value="3" />
<label for="permissions_2__permission_value">Role-Edit</label>
<input data-val="true" data-val-required="The Boolean field is required." id="permissions_2__permission_value" name="permissions[2].permission_value"
type="checkbox" value="true" /><input name="permissions[2].permission_value" type="hidden" value="false" />
</div>
Finally here is the Create POST method
[HttpPost]
public ActionResult Create(RoleVM rolevm)
{
//In here rolevm.role is populated based on the textbox input
//However rolevm.permissions is there with the correct
//number of items, but the values all are not binded
// id is null, name is empty, and permission_value is false
// regardless of which checkboxes were checked
return RedirectToAction("Index");
}
Any help on the binding issue with the posted model would be really great.
This was a simple issue, if someone else comes across it maybe this will help them. I didn't have the properties on the class declared as properties with get; set;
public class RolePermission {
public int id { get; set; }
public bool permission_value { get; set; }
public string name { get; set; }
}