mvc 5, model is List, submited model is null - c#

I need to submit list of skills. when i try to do this submitted model is null. But in Fidler I see that data was send.
public class MvcSkill
{
[HiddenInput(DisplayValue = false)]
public int Id { get; set; }
[Display(Name = "Category Name")]
[StringLength(128, ErrorMessage = "Max length - {0} symbols")]
[Required(ErrorMessage = "Please enter your last name")]
public string Name { get; set; }
public int Level { get; set; }
[Required(ErrorMessage ="Choose skill category")]
public string CategoryName { get; set; }
}
Partial view for each skill (strange input for skill level is bootstrap-star-rating:
#using MvcApp.Infrastructure;
#model MvcApp.ViewModels.MvcSkill
<tr>
<td>
#Html.HiddenFor(x => x.Id)
</td>
<td>
#Html.HiddenFor(x => x.Name)
#Html.DisplayFor(x => x.Name)
</td>
<td>
#Html.HiddenFor(x => x.CategoryName)
#Html.DisplayFor(x => x.CategoryName)
</td>
<td>
<input for="Level" id="#Model.Id" value="#Model.Level" name="Level" type="number" class="rating-loading" data-size="xs" data-min="0" data-max="5" data-step="1" data-show-clear="false">
</td>
#{
var identity = (CustomIdentity)User.Identity;
if (identity.Roles.FirstOrDefault(r => r == "Administrator") != null)
{
<td>
#Html.RouteLink("Edit", new { controller = "Administrator", action = "EditSkill", id = Model.Id })
</td>
<td>
#Html.RouteLink("Remove", new { controller = "Administrator", action = "RemoveSkill", id = Model.Id })
</td>
}
}
</tr>
View for list of skills:
#model IList<MvcApp.ViewModels.MvcSkill>
#{
ViewBag.Title = "Skills";
}
#using (Html.BeginForm("Index","Skill", Model))
{
<table>
#foreach (var s in Model)
{
#Html.Partial("_Skill", s)
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input id="submit" type="submit" value="Update" class="btn btn-default" />
</div>
</div>
}
#section scripts{
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" rel="stylesheet">
<link href="~/Content/star-rating.css" media="all" rel="stylesheet" type="text/css" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js"></script>
<script src="~/Scripts/star-rating.js" type="text/javascript"></script>
#foreach (var item in Model)
{
string id = item.Id.ToString();
<script>
$(document).on('ready', function () {
$('##id').rating({
step: 1,
defaultCaption: 'Unknown',
starCaptions: { 0: 'Unknown', 1: 'Beginner', 2: 'Elementary', 3: 'Intermediate', 4: 'Advanced', 5: 'Profi' },
starCaptionClasses: function (val) { return 'text-success'; }
}).on('rating.change', function (event, value, caption) {
Model.Skills.FirstOrDefault(s => s.Key.Id.ToString() == id).Value = value;
});
});
</script>
}
}
And controller method:
[HttpPost]
public ActionResult Index(List<MvcSkill> skillModel)
{
//Do something...
return View();
}
Fidler text:
Id=1&Name=c%2B%2B&CategoryName=Programing&Level=5&Id=3&Name=PHP&CategoryName=Programing&Level=3&Id=6&Name=JAVA&CategoryName=Programing&Level=3&Id=7&Name=Name&CategoryName=.Net+Frameworks&Level=5

You have to manually add indexes so MVC framework can successfully bind data. Something like:
#using (Html.BeginForm("Index","Skill", Model))
{
<table>
#for (int i = 0; i < Model.Length; i++)
{
<tr>
<td>
#Html.Hidden("[" + i + "].Id");
</td>
<td>
#Html.DisplayFor(m => Model.ElementAt(i).Name)
#Html.Hidden("[" + i + "].Name");
</td>
<td>
#Html.DisplayFor(m => Model.ElementAt(i).CategoryName)
#Html.Hidden("[" + i + "].CategoryName");
</td>
</tr>
}
</table>
}
Or, as stated in comments you can use BeginCollectionItem (which I personally use). What BeginCollectionItem does is, generally it adds GUIDs as index fro you. Source code can be found here and you can get familiar with it here.

Related

Access view model data in controller

In my application I have created a view model to show data in the View.
I created view model as this.
[NotMapped]
public class EmpExcelUploadViewModel {
public int CompanyId {
get;
set;
}
public int EmpNo {
get;
set;
}
public string EmpName {
get;
set;
}
public int EmpDep {
get;
set;
}
public int EmpDes {
get;
set;
}
}
In the controller I have assigned data to the view model and passed to the view. Just to show the data to the user, there is no editing or deleting data from the user view. That stage is works fine.
This is the view
#model IEnumerable
<Asp_PASMVC.ViewModels.EmpExcelUploadViewModel>
#{
ViewBag.Title = "Import";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
#using (Html.BeginForm("Import", "M_Employee", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="card card-primary">
<div class="card-header">
<h1 class="card-title"><b>Upload Employees from Excel</b></h1>
</div>
<div>
<br />
#Html.Raw(ViewBag.Error)
<h4><span>Select Excel File</span></h4>
<input type="file" name="excelFile" class="btn btn-warning" />
<br />
</div>
<div class="row">
<div class="col-md-1">
<br />
<br />
<input type="submit" value="Import" class="btn btn-info" />
</div>
<div class="col-md-1">
<br />
<br />
<input type="button" value="Upload" class="btn btn-success" onclick="location.href='#Url.Action("UploadEmployees", "M_Employee")'" />
</div>
</div>
<div class="card-body p-0">
<table class="table table-striped">
<tr>
<th>Company</th>
<th>EmpId</th>
<th>EmpName</th>
<th>Department</th>
<th>Dessignation</th>
</tr>
#if (ViewBag.EmpList != null)
{
foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CompanyId)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmpNo)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmpName)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmpDep)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmpDes)
</td>
</tr>
}
}
</table>
</div>
<!-- /.card-body -->
</div>
}
</div>
I want to know, when user clicks to the Upload button, that the data already in the view model I want to pass to the database. So how can I access the data already in the view model? I'm still learning MVC and I don't know if it's possible or not.
This is what I tried. Here in the empExcel getting error that EmpExcelUploadViewModel does not contain public instance.
public ActionResult UploadEmployees(EmpExcelUploadViewModel empExcel) {
try {
foreach(var item in empExcel) // error in empExcel {
int ComId = item.CompanyId;
int EmpNo = item.EmpNo;
string EmpName = item.EmpName;
int DepId = item.EmpDep;
int DesId = item.EmpDes;
var isEmployeeExists = (from e in db.CreateEmployee where e.EmpNo == EmpNo select e.Id).First();
if (isEmployeeExists != 0) {
M_Employee e = new M_Employee();
e.CompanyId = ComId;
e.EmpNo = EmpNo;
e.EmpName = EmpName;
e.DepId = DepId;
e.DesignId = DesId;
e.Status = true;
e.CreateDate = DateTime.Now;
e.CreateBy = int.Parse(((System.Security.Claims.ClaimsIdentity) User.Identity).FindFirst("UserId").Value);
db.CreateEmployee.Add(e);
db.SaveChanges();
} else {
M_Employee m_Employee = db.CreateEmployee.First(x => x.Id == isEmployeeExists);
m_Employee.DepId = DepId;
m_Employee.DesignId = DesId;
db.SaveChanges();
}
}
} catch (Exception ex) {
ViewBag.Error = "Error " + ex;
}
ViewBag.Error = "All Records uploaded to the database";
ViewBag.EmpList = null;
return View("Import");
}
}
Instead of saving data in the view, you should do it in the controller.
In the controller, if there's any error saving the data to the database, set a separate error flag indicating this. Then, the View uses this flag to determine what to display

How can i fill a table with values from a dropdownlist in ASP.NET Core MVC

I want to fill an html table with the selecteditem from a dropdownlist, I already passed the database data to this list, and I also get all the information of the selected value through an actionresult, so the thing I want is when I select an item, put it in the table, and do this every time I want so I can add various values at the same time. does anyone have any idea how to do it?
This is my model
public partial class Producto
{
public int Id { get; set; }
public string Nombre { get; set; }
public string Descripcion { get; set; }
public string Precio { get; set; }
[NotMapped]
public List <Producto> Listasnom { get; set; }
[NotMapped]
public IEnumerable < SelectListItem > ProductoListItems
{
get
{
return new SelectList(Listasnom ?? new List<Producto>(), "Id", "Nombre");
}
}
}
My controller
MyDbContext db = new MyDbContext();
[HttpGet]
public ActionResult Index()
{
return View(db.Pedido.ToList());
}
public ActionResult Create()
{
var lista = new Producto();
lista.Listasnom = db.Producto.ToList();
return View(lista);
}
[HttpPost]
public ActionResult Create(Producto producto)
{
var lista = new Producto();
lista.Listasnom = db.Producto.ToList();
var emp = lista.Listasnom.Where(e => e.Id == producto.Id).FirstOrDefault();
lista.Id = emp.Id;
lista.Nombre = emp.Nombre;
lista.Precio = emp.Precio;
return View(lista);
}
and my view:
#model punto.Models.Producto
<form class="form-horizontal" method="post" action="">
<div class="box-body">
<div class="form-group">
<label for="inputEmail3" class="col-sm-1 control-label">Producto</label>
<div class="col-sm-10">
#Html.DropDownListFor(model => model.Id, Model.ProductoListItems, "Elegir Producto", new { #class = "form-control"})
</div>
<button type="submit" class="btn btn-info">Agregar</button>
</div>
</form>
This is the table where I want to put the values
<table id="example1" class="table table-bordered table-responsive">
<thead>
<tr>
<th>Id</th>
<th>Producto</th>
<th>Precio</th>
</tr>
</thead>
<tbody>
<tr>
<td>#Html.DisplayFor(model => model.Id)</td>
<td>#Html.DisplayFor(model => model.Nombre)</td>
<td>#Html.DisplayFor(model => model.Precio) </td>
</tr>
</table>
I don't have any idea how to do it, if someone can help me.
If you want to select more products and store them in the table , you could try to use ajax as Nhien said :
View :
#model WebApplication2.Models.Producto
<div class="box-body">
<div class="form-group">
<label for="inputEmail3" class="col-sm-1 control-label">Producto</label>
<div class="col-sm-10">
#Html.DropDownListFor(model => model.Id, Model.ProductoListItems, "Elegir Producto", new { #class = "form-control",id="selectlist" })
</div>
<button type="submit" id="btnCreate" class="btn btn-info">Agregar</button>
</div>
</div>
<table id="example1" class="table table-bordered table-responsive">
<thead>
<tr>
<th>Id</th>
<th>Producto</th>
<th>Precio</th>
</tr>
</thead>
<tbody> </tbody>
</table>
#section Scripts
{
<script type="text/javascript">
$("#selectlist").change(function () {
var id = $("#selectlist").val()
$.ajax({
type: "get",
url: "/products/getproduct?id=" + id,
success: function (data) {
var tBody = $("#example1 > TBODY")[0];
var row = tBody.insertRow(-1);
//Add ID cell.
var cell = $(row.insertCell(0));
cell.html(data.id);
//Add Nombre cell.
cell = $(row.insertCell(1));
cell.html(data.nombre);
//Add Precio cell.
cell = $(row.insertCell(2));
cell.html(data.precio);
}
});
});
</script>
}
Controller :
public IActionResult GetProduct(int id)
{
var selectProduct = db.Producto.Find(id);
return Json(selectProduct);
}

In MVC/Razor, how do I get the values of multiple checkboxes and pass them all to the controller?

I have a view with a list of items from a model. I need to add a checkbox to each row, have the user select multiple check boxes, and pass some identifier of what row was selected to the controller. I know how to pass a single value through an action link, but I'm not sure how to pass multiple values through an action link or how to "collect" which rows were selected. I'll show some of my code attempts below. Can someone help me sort out why I can't get the values of all the checkboxes passed to the controller?
Here's my page
Checkbox App ID Date Name
[] 1 5/10 Bob
[] 2 5/10 Ted
[] 3 5/11 Alice
What I need the user to do is select rows 1 & 3 (for example) and have those App ID's passed to the controller.
I started listing various attempts, but decided just to show my current attempt and see if anyone could point out what I'm doing wrong. The main difference I see between examples online and mine is that mine uses a PagedList and creates the rows of the table in a foreach loop.
The parameter ints is blank when it hits the controller. How do I get the values from the checkboxes into it? I used this site for the basic idea of naming all the checkboxes the same and passing a ICollection through the action link:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
View:
#model PagedList.IPagedList<CarmelFinancialWeb.Models.ModelMerchantSummary>
<div class="block" style="width: 100%; float: left">
<p class="block-heading">
Merchant Application Report
</p>
<div class="table-holder">
<table class="table" style="margin-bottom: 0px">
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<input type="checkbox" name="ints" value=item.ApplicationID />
</td>
<td>
#Html.ActionLink(item.ApplicationID.ToString(), "ViewApplication", new { ID = item.ApplicationID, edit = 1 }, new AjaxOptions { HttpMethod = "GET" })
</td>
<td>
#Convert.ToDateTime(item.ApplicationDate).ToString("M/d/yy")
</td>
<td>
#item.ApplicantName
</td>
</tbody>
</table>
</div>
</div>
#Html.ActionLink("Print Application", "PrintApplication", "CreateContract", new { #class = "btn btn-primary" })
Controller:
[AuthorizeAdmin]
public ActionResult PrintApplication(ICollection<int> ints, string ID)
{
Contracts_Create contract = new Contracts_Create();
ModelApplication currentApplication = new ModelApplication();
currentApplication.contract = new ModelContract();
return File(contract.CreatePDF_PrintedApplication_English(currentApplication.contract.location, currentApplication.contract), "application/pdf");
}
Edit:
This got tagged as a duplicate of another question. The question there was about whether non-sequential input names could be used. My problem is that I'm using inputs that are not non-sequential, but it is still not working. I understand the concept, I just can't figure out why my specific code is not working. I've put a lot of time into this and can't find the answer to my specific code. Thanks!
Try passing a ViewModel into your page, and using the model binder to post the same view model back into your controller
Models:
public class MerchantModel
{
public int AppId { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class MerchantViewModel
{
public List<MerchantModel> Merchants { get; set; }
}
Controller:
public class DefaultController : Controller
{
// GET: Default
public ActionResult Index()
{
var merchant1 = new MerchantModel
{
AppId = 1,
Name = "Bob"
};
var merchant2 = new MerchantModel
{
AppId = 2,
Name = "Ted"
};
var merchant3 = new MerchantModel
{
AppId = 3,
Name = "Alice"
};
List<MerchantModel> list = new List<MerchantModel>();
list.Add(merchant1);
list.Add(merchant2);
list.Add(merchant3);
var model = new MerchantViewModel
{
Merchants = list
};
return View(model);
}
[HttpPost]
public ActionResult Index(MerchantViewModel model)
{
return View(model);
}
}
View:
#model TestCheckBoxes.Models.MerchantViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<form action="/default/index" method="post">
<table>
#for (int i = 0; i < Model.Merchants.Count; i++)
{
<tr>
<td>
#Html.CheckBoxFor(x => x.Merchants[i].IsSelected)
</td>
<td>
#Html.HiddenFor(x => x.Merchants[i].AppId)
#Model.Merchants[i].AppId
</td>
<td>
#Html.HiddenFor(x => x.Merchants[i].Name)
#Model.Merchants[i].Name
</td>
</tr>
}
</table>
<button type="submit">Submit</button>
</form>
</div>
</body>
</html>
Back in your [HttpPost] method in your controller, you will have a list of MerchantModel's with the bool value either true or false. This way you can check if it's true and just grab the AppId from there.
Don't use foreach in mvc, always iterate using for and an indexing variable.
You'll also need a bool to track the selection status.
This example code works for me:
public class AModel
{
public List<AnotherModel> Items { get; set; }
}
public class AnotherModel
{
public int ApplicationId { get;set; }
public DateTime ApplicationDate { get; set; }
public string ApplicantName { get; set; }
public bool Selected { get; set; }
}
Page.cshtml
#using (Html.BeginForm("PostIndex", "Home", FormMethod.Post))
{
<table class="table" style="margin-bottom: 0px">
<tbody>
#for (var i = 0; i < Model.Items.Count(); i++)
{
<tr>
<td>
<label>#Html.CheckBoxFor(model => model.Items[i].Selected) #Html.DisplayFor(model => model.Items[i].ApplicantName)</label>
</td>
<td>
#Html.ActionLink(Model.Items[i].ApplicationId.ToString(), "ViewApplication", new {ID = Model.Items[i].ApplicationId, edit = 1}, new AjaxOptions {HttpMethod = "GET"})
</td>
<td>
#Html.DisplayFor(model => model.Items[i].ApplicationDate)
</td>
<td>
#Html.DisplayFor(model => model.Items[i].ApplicationId)
</td>
</tr>
}
</tbody>
</table>
<input type="submit"/>
}
#CBauer and #NickYoung essentially had the answer. The keys were (1) making sure my checkboxes had the ID written with a sequential number in brackets with the same suffix, (2) using a submit button instead of an action link, and (3) correctly writing the controller to accept the IDs from the checkboxes. Thought I'd post some of my code to give you an idea of what I got to work:
View (partial):
#model PagedList.IPagedList<CarmelFinancialWeb.Models.ModelMerchantSummary>
...
#{var i = 0;}
#foreach (var item in Model)
{
var tmp = "[" + i + "].ints";
<tr>
<td>
<input name="ints" type="checkbox" id="#tmp" class="chkclass" value="#item.ApplicationID" />
</td>
...
<input id="Submit" type="submit" class="btn btn-primary" value="Print Application(s)" />
...
Controller:
[AuthorizeAdmin]
[HttpPost]
public ActionResult MerchantApplicationSummary(string[] ints, FormCollection form, int? page)
{
...
Thanks #CBauer and #NickYoung for your help!

How can I post a list of items in MVC

I have a simple form with a list of items in it and I'd like to post them to the controller but funny thing is I just cant. Everything else goes through properly except the list. I checked the ajax call in firebug and the post values are there like this:
Answers[0].IsMissing False
Answers[0].Text Ja
Answers[0].Value 0
Answers[1].IsMissing False
Answers[1].Text Nein
Answers[1].Value 1
Id 1cd14b08-ce3b-4671-8cf8-1bcf69f12b2d
Name Ja/Nein
I have an AnwserScheme class with the following properties:
public string Name { get; set; }
public bool IsMissing { get; set; }
public List<AnswerDisplayItem> Answers { get; set; }
public AnswerScheme()
{
Answers = new List<AnswerDisplayItem>();
}
I have this view code:
#for (int i = 0; i < Model.Answers.Count; i++) {
<tr>
<td>
#Html.HiddenFor(model => Model.Answers[i].IsMissing)
#Html.TextBoxFor(model => Model.Answers[i].Value,
new { #class = "inputValue" })
</td>
<td>
#Html.TextBoxFor(model => Model.Answers[i].Text,
new { #class = "inputAnswer" })
</td>
<td>
<span class="span-delete"
data-answer-scheme-id="#Model.Id"
data-answer-id="#Model.Answers[i].Id" >x</span>
</td>
</tr>
}
I have this piece of ajax code that is responsible for posting:
$.ajax({
url: "/AnswerScheme/AddAnswer",
type: "post",
data: $("#formAnswerScheme").serialize(),
success: function (data) {
console.log(data);
$("#divAnswerSchemeContainer").html(data);
}
});
I have an add answer action in my controller:
[HttpPost]
public PartialViewResult AddAnswer(AnswerScheme answerScheme)
{
...some logic comes here
}
So in the end the controller recieves the model, but only the simple properties, not the list. Any help would be greatly appreciated! cheers.
I wish I could see more of your classes and code, because you don't have something set up right.
I recreated something from what you did provide, which works. I created an MVC 3 project for this sample.
Views/Shared/_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
</head>
<body>
#RenderBody()
</body>
</html>
Views/Shared/_Partial.cshtml
#model RazorListTest.Models.AnswerScheme
<table>
#for (int i = 0; i < Model.Answers.Count; i++) {
<tr>
<td>
#Html.HiddenFor(model => Model.Answers[i].IsMissing)
#Html.TextBoxFor(model => Model.Answers[i].Value, new { #class = "inputValue" })
</td>
<td>
#Html.TextBoxFor(model => Model.Answers[i].Text, new { #class = "inputAnswer" })
</td>
<td><span class="span-delete" data-answer-scheme-id="#Model.Id" data-answer-id="#Model.Answers[i].Id" >x</span></td>
</tr>
}
</table>
Models/AnswerDisplayItem.cs
using System.Collections.Generic;
namespace RazorListTest.Models
{
public class AnswerDisplayItem
{
public bool IsMissing { get; set; }
public string Text { get; set; }
public string Value { get; set; }
public string Id { get; set; }
}
public class AnswerScheme
{
public List<AnswerDisplayItem> Answers { get; set; }
public string Id { get; set; }
public AnswerScheme()
{
Answers = new List<AnswerDisplayItem>();
}
}
}
Home/Index.cshtml
#model RazorListTest.Models.AnswerScheme
#using (Html.BeginForm(null, null, FormMethod.Get, new { name="formAnswerScheme", id = "formAnswerScheme"}))
{
{Html.RenderPartial("_Partial");}
<div>
<input type="button" value="Click me" id="btnClick"/>
</div>
<div id="divAnswerSchemeContainer">
</div>
}
<script type="text/javascript">
$("#btnClick").click(function () {
$.ajax({
url: 'Home/AddAnswer',
type: 'POST',
dataType: 'json',
data: $("#formAnswerScheme").serialize(),
success: function (data) {
console.log(data);
$("#divAnswerSchemeContainer").html(data);
},
error: function (xhr, textStatus, exceptionThrown) { alert(JSON.parse(xhr.responseText)); }
});
});
</script>
Controllers/HomeController.cs
using System.Collections.Generic;
using System.Web.Mvc;
using RazorListTest.Models;
namespace RazorListTest.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
AnswerScheme a = new AnswerScheme();
a.Id = "1cd14b08-ce3b-4671-8cf8-1bcf69f12b2d";
List<AnswerDisplayItem> adi = new List<AnswerDisplayItem>();
AnswerDisplayItem a1 = new AnswerDisplayItem();
a1.IsMissing = false;
a1.Text = "Ja";
a1.Value = "0";
a1.Id = "1234";
AnswerDisplayItem a2 = new AnswerDisplayItem();
a2.IsMissing = false;
a2.Text = "Nein";
a2.Value = "1";
a2.Id = "5678";
adi.Add(a1);
adi.Add(a2);
a.Answers = adi;
return View(a);
}
[HttpPost]
public JsonResult AddAnswer(AnswerScheme answerScheme)
{
return Json("the list is in the Model.");
}
}
}
Its almost identical what TheGeekYouNeed posted, but i guess something is just missing. I have no clue what that could be.
AnswerScheme view:
#using System.Web.Mvc.Html
#using MetaDataPortal.Models
#model AnswerScheme
#{
ViewBag.Title = #Model.IsMissing ? "Missing" : "AnswerScheme";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section CssContent{
<link href="../../Content/CSS/AnswerScheme.css" rel="stylesheet" />
}
#using (Html.BeginForm("Save", "AnswerScheme", FormMethod.Post, new { id = "formAnswerScheme" })) {
<div id="divAnswerSchemeContainer">
#{Html.RenderPartial("_AnswerScheme", Model);}
</div>
<input type="button" class="clear inputButton" id="buttonAddCode" value="Add #(Model.IsMissing ? "Missing" : "Answer")" />
<input type="submit" value="Save" />
}
#section Javascript{
<script type="text/javascript">
$(function () {
$("#buttonAddCode").click(function () {
$.ajax({
url: "/AnswerScheme/AddAnswer",
type: "post",
async: false,
data: $("#formAnswerScheme").serialize(),
success: function (data) {
console.log(data);
$("#divAnswerSchemeContainer").html(data);
}
});
return false;
});
});
</script>
<script type="text/javascript" src="~/Content/JavaScript/AnswerScheme.js"></script>
}
_AnswerScheme partialview
#model MetaDataPortal.Models.AnswerScheme
#Html.HiddenFor(model => model.Id, new { Id = "AnswerSchemeId" })
<ul class="ulGeneralForm">
<li>
#Html.LabelFor(model => model.Name, "Name", new { #class = "labelGeneral" })
#Html.TextBoxFor(model => model.Name, Model.Name, new { #class = "textBoxGeneral" })
</li>
<li>
#Html.Label(#Model.IsMissing ? "Missings" : "Answers", new { #class = "labelGeneral" })
<table class="textualData links downloadList">
<thead>
<tr>
<th>Value</th>
<th> #(Model.IsMissing ? "Missing" : "Answer")</th>
<th></th>
</tr>
</thead>
<tbody id="tbodyCodeContainer">
#for (int i = 0; i < Model.Answers.Count; i++) {
<tr>
<td>
#Html.HiddenFor(model => Model.Answers[i].IsMissing)
#Html.TextBoxFor(model => Model.Answers[i].Value, new { #class = "inputValue" })
</td>
<td>
#Html.TextBoxFor(model => Model.Answers[i].Text, new { #class = "inputAnswer" })
</td>
<td><span class="span-delete" data-answer-scheme-id="#Model.Id" data-answer-id="#Model.Answers[i].Id" >x</span></td>
</tr>
}
</tbody>
</table>
</li>
</ul>
AnswerScheme.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using Opit.Rogatus.DomainObjects;
namespace MetaDataPortal.Models
{
public class AnswerScheme : BaseModel
{
public string Name { get; set; }
public bool IsMissing { get; set; }
public List<AnswerDisplayItem> Answers { get; set; }
public AnswerScheme()
{
Answers = new List<AnswerDisplayItem>();
}
public AnswerScheme(CodeList codeList, bool isMissing) : this()
{
Id = codeList.Id;
Name = codeList.Name;
IsMissing = isMissing;
foreach (Code code in codeList.Codes.Where(code => code.Category.IsMissing == isMissing))
{
Answers.Add(new AnswerDisplayItem(code));
}
}
}
}
AnswerDisplayItem.cs:
using System;
using Opit.Rogatus.DomainObjects;
namespace MetaDataPortal.Models
{
public class AnswerDisplayItem
{
public Guid Id { get; private set; }
public short Value { get; private set; }
public string Text { get; private set; }
public Guid AnswerSchemeId { get; set; }
public bool IsMissing { get; private set; }
public AnswerDisplayItem()
{
}
public AnswerDisplayItem(Code code)
{
Id = code.Id;
Value = code.Value;
Text = code.Category.Name;
IsMissing = code.Category.IsMissing;
if (code.CodeList == null) return;
AnswerSchemeId = code.CodeList.Id;
}
}
}
And controller is pretty much the same.
You can do like this create model
public class ApplicationInfo
{
public List<ApplicationAccessRoles> ApplAccessRoleInfo { get; set; }
}
public class ApplicationAccessRoles
{
public int app_access_role_key { get; set; }
public int app_key { get; set; }
public string access_role { get; set; }
public bool inactive { get; set; }
}
put it in view
<div class="step-pane" id="step3">
<div class="form-horizontal" style="vertical-align:central;margin-left:150px">
<table id="RolesDetails" cellpadding="0" cellspacing="0" class="data_table">
<tr class="dataheader">
<td class="width5">
#Html.HiddenFor(m => m.app_access_role_key)
</td>
<td class="width200">
Access Roles Name
</td>
<td class="width10">
Inactive
</td>
</tr>
#if (Model.ApplAccessRoleInfo.Count!= 0)
{
var chk = Model.ApplAccessRoleInfo.Count;
for (int a = 0; a < Model.ApplAccessRoleInfo.Count; a++)
{
<tr class="exp_col_header top_border_nil">
#if ((chk - 1) == a)
{
<td></td>
}
else
{
<td></td>
}
<td>
#Html.HiddenFor(m => m.ApplAccessRoleInfo[a].app_access_role_key)
#Html.EditorFor(m => m.ApplAccessRoleInfo[a].access_role)
</td>
<td>
#Html.CheckBox("ApplTeamAccessInfo[" + a.ToString() + "].inactive", false, new { #class = "check-box"})
</td>
</tr>
}
}
else
{
<tr class="exp_col_header top_border_nil">
<td>
</td>
<td>
#*#Html.EditorFor(model => model.access_role)*#
#*#Html.EditorFor(m => m.ApplAccessRoleInfo[0].access_role)*#
#Html.EditorFor(model=>model.access_role)
</td>
<td>
#Html.CheckBoxFor(model => model.inactive)
</td>
</tr>
}
</table>
</div>
</div>
In Controller
var main = (from a in db.mas_app_access_roles
where a.app_key == AppInfo.app_key
select new ApplicationAccessRoles
{
app_access_role_key = a.app_access_role_key,
access_role = a.access_role,
inactive = a.inactive,
}).ToList();
access = main;
AppInfo.ApplAccessRoleInfo = access;
ViewBag.check = access;
return View(AppInfo);
The problem is with the name/id attribute of your text boxes and other input controls. You can use editor templates to make things seamless and reusable.. Another example here.
But if you still want to loop through things, your loop has to look something in these examples here or here.
Try changing either the controller parameter name to "answers" or the property name to AnswerScheme and if the partial controller in your post is supposed to be recieving the list then change the type to:
List<AnswerScheme> answers

MVC3 model binder fails to bind Dictionary<string, bool> that is part of my ViewModel

I can't figure out what I'm messing up. The FormCollection seems to show everything is right. RoleName comes back fine, too. So why is RoleMembership coming back null?
Model:
public class EditRoleMembershipViewModel
{
public string RoleName { get; set; }
public Dictionary<string, bool> RoleMembership { get; set; }
}
Controller Action:
[HttpGet]
public ActionResult EditRoleMembership(string roleName)
{
var viewModel = new EditRoleMembershipViewModel {RoleName = roleName};
var allUsers = _userServices.GetAllUsers();
getRolesForUsers(allUsers);
var role = _roleServices.GetRole(roleName);
viewModel.RoleMembership = new Dictionary<string, bool>();
foreach (var user in allUsers)
{
var isMember = user.Roles != null && user.Roles.Contains(role);
viewModel.RoleMembership.Add(user.UserName, isMember);
}
return View(viewModel);
}
View:
#model CI.Portal.Mvc.ViewModels.EditRoleMembershipViewModel
#{
ViewBag.Title = "Edit Role";
}
<h2>#ViewBag.Title: #Model.RoleName</h2>
<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>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
<thead>
<tr>
<th>
</th>
<th>
In Role
</th>
</tr>
</thead>
<tbody>
#{
int index = 0;
foreach (var item in Model.RoleMembership)
{
<tr>
<td>
#item.Key
#Html.Hidden(string.Format("model.RoleMembership[{0}].Key", index), item.Key)
</td>
<td>#Html.CheckBox(string.Format("model.RoleMembership[{0}].Value", index), item.Value)</td>
</tr>
index++;
}
}
</tbody>
</table>
<p>
<input type="submit" value="Save" />
</p>
}
<div>
#Html.ActionLink("Back to Details", "RoleDetails", new { Model.RoleName })
</div>
Could you try removing the "model." prefix from the checkbox helper declaration.
Instead of
<td>
#item.Key
#Html.Hidden(string.Format("model.RoleMembership[{0}].Key", index), item.Key)
</td>
<td>
#Html.CheckBox(string.Format("model.RoleMembership[{0}].Value", index), item.Value)
</td>
Do this:
<td>
#item.Key
#Html.Hidden(string.Format("RoleMembership[{0}].Key", index), item.Key)
</td>
<td>
#Html.CheckBox(string.Format("RoleMembership[{0}].Value", index), item.Value)
</td>

Categories