MVC post a list of complex objects - asp.net-mvc

I have a FeedbackViewModel that contains a list of questions:
public class FeedbackViewModel
{
public List<QuestionViewModel> Questions { get; set; }
}
This QuestionViewModel is an object that can be inherited by 5 different types of questions
public class QuestionViewModel
{
public string QuestionText { get; set; }
public string QuestionType { get; set; }
}
An example of one of the inheriting question types:
public class SingleQuestionViewModel : QuestionViewModel
{
public string AnswerText { get; set; }
}
In the HttpGet of the Index action in the controller I get the questions from the database and add the correct question type in list of question in the FeedbackViewModel Then I render this model in the view:
#using (Html.BeginForm())
{
//foreach (var item in Model.Questions)
for (int i = 0; i < Model.Questions.Count; i++)
{
<div class="form-group">
#Html.DisplayFor(modelItem => Model.Questions[i].QuestionText, new { #class = "control-label col-md-4" })
<div class="col-md-6">
#if (Model.Questions[i].QuestionType == "Single")
{
#Html.EditorFor(modelItem => (Model.Questions[i] as OpenDataPortal.ViewModels.SingleQuestionViewModel).AnswerText)
}
else if (Model.Questions[i].QuestionType == "Multiple")
{
#Html.TextAreaFor(modelItem => (Model.Questions[i] as OpenDataPortal.ViewModels.SingleQuestionViewModel).AnswerText)
}
else if (Model.Questions[i].QuestionType == "SingleSelection")
{
#Html.RadioButtonForSelectList(modelItem => (Model.Questions[i] as OpenDataPortal.ViewModels.SingleSelectionQuestionViewModel).SelectedAnswer,
(Model.Questions[i] as OpenDataPortal.ViewModels.SingleSelectionQuestionViewModel).SelectionAnswers)
}
else if (Model.Questions[i].QuestionType == "MultipleSelection")
{
#Html.CustomCheckBoxList((Model.Questions[i] as OpenDataPortal.ViewModels.MultipleSelectionQuestionViewModel).AvailableAnswers)
}
else if (Model.Questions[i].QuestionType == "UrlReferrer")
{
#Html.EditorFor(modelItem => (Model.Questions[i] as OpenDataPortal.ViewModels.SingleQuestionViewModel).AnswerText)
}
</div>
</div>
<br />
}
<br />
<button type="submit">Submit</button>
}
Now, I simply can't get it to post the list of questions in the model. Is it even possible to post a list of different object types?
Edit: Following is the list of data within the post that I discovered using Fiddler:

After much research I've found two solutions:
One is to write HTML that has hardcoded Id's and Names
Two is to convert your ICollection/IEnumerable to an Array or List (i.e IList something with an 'index'), and have an Array object in your BindingModel in your Controller POST Action.
Thanks to Phil Haack's (#haacked) 2008 blog post http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
Which is still relevant to how the default ModelBinder works today for MVC.
(NB: the links in Phil's article to sample porject and extension methods are broken)
HTML snippet that inspired me:
<form method="post" action="/Home/Create">
<input type="hidden" name="products.Index" value="cold" />
<input type="text" name="products[cold].Name" value="Beer" />
<input type="text" name="products[cold].Price" value="7.32" />
<input type="hidden" name="products.Index" value="123" />
<input type="text" name="products[123].Name" value="Chips" />
<input type="text" name="products[123].Price" value="2.23" />
<input type="submit" />
</form>
Post array looks a bit like:
products.Index=cold&products[cold].Name=Beer&products[cold].Price=7.32&products.Index=123&products[123].Name=Chips&products[123].Price=2.23
Model:
public class CreditorViewModel
{
public CreditorViewModel()
{
this.Claims = new HashSet<CreditorClaimViewModel>();
}
[Key]
public int CreditorId { get; set; }
public string Comments { get; set; }
public ICollection<CreditorClaimViewModel> Claims { get; set; }
public CreditorClaimViewModel[] ClaimsArray {
get { return Claims.ToArray(); }
}
}
public class CreditorClaimViewModel
{
[Key]
public int CreditorClaimId { get; set; }
public string CreditorClaimType { get; set; }
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:N2}")]
public Decimal ClaimedTotalAmount { get; set; }
}
Controller GET:
public async Task<ActionResult> Edit(int id)
{
var testmodel = new CreditorViewModel
{
CreditorId = 1,
Comments = "test",
Claims = new HashSet<CreditorClaimViewModel>{
new CreditorClaimViewModel{ CreditorClaimId=1, CreditorClaimType="1", ClaimedTotalAmount=0.00M},
new CreditorClaimViewModel{ CreditorClaimId=2, CreditorClaimType="2", ClaimedTotalAmount=0.00M},
}
};
return View(model);
}
Edit.cshtml:
#Html.DisplayNameFor(m => m.Comments)
#Html.EditorFor(m => m.Comments)
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(m => Model.Claims.FirstOrDefault().CreditorClaimType)
</th>
<th>
#Html.DisplayNameFor(m => Model.Claims.FirstOrDefault().ClaimedTotalAmount)
</th>
</tr>
<!--Option One-->
#foreach (var item in Model.Claims)
{
var fieldPrefix = string.Format("{0}[{1}].", "Claims", item.CreditorClaimId);
<tr>
<td>
#Html.DisplayFor(m => item.CreditorClaimType)
</td>
<td>
#Html.TextBox(fieldPrefix + "ClaimedTotalAmount", item.ClaimedTotalAmount.ToString("F"),
new
{
#class = "text-box single-line",
data_val = "true",
data_val_number = "The field ClaimedTotalAmount must be a number.",
data_val_required = "The ClaimedTotalAmount field is required."
})
#Html.Hidden(name: "Claims.index", value: item.CreditorClaimId, htmlAttributes: null)
#Html.Hidden(name: fieldPrefix + "CreditorClaimId", value: item.CreditorClaimId, htmlAttributes: null)
</td>
</tr>
}
</table>
<!--Option Two-->
#for (var itemCnt = 0; itemCnt < Model.ClaimsArray.Count(); itemCnt++)
{
<tr>
<td></td>
<td>
#Html.TextBoxFor(m => Model.ClaimsArray[itemCnt].ClaimedTotalAmount)
#Html.HiddenFor(m => Model.ClaimsArray[itemCnt].CreditorClaimId)
</td></tr>
}
Form is processed in the Controller:
Post Model:
public class CreditorPostViewModel
{
public int CreditorId { get; set; }
public string Comments { get; set; }
public ICollection<CreditorClaimPostViewModel> Claims { get; set; }
public CreditorClaimPostViewModel[] ClaimsArray { get; set; }
}
public class CreditorClaimPostViewModel
{
public int CreditorClaimId { get; set; }
public Decimal ClaimedTotalAmount { get; set; }
}
Controller:
[HttpPost]
public ActionResult Edit(int id, CreditorPostViewModel creditorVm)
{
//...

Make sure you are rendering your view in order so that Model.Questions[i] renders in order.
For example, Model.Questions[0], Model.Questions[1], Model.Questions[2].
I noticed that if the order is not correct mvc model binder will only bind the first element.

Thanks for pointing me in the right direction with this post. I was struggling to get the syntax right for binding a non-sequential IDictionary<string, bool> object. Not sure this is 100% correct, but this Razor code worked for me:
<input type="hidden" name="MyDictionary.Index" value="ABC" />
<input type="hidden" name="MyDictionary[ABC].Key" value="ABC" />
#Html.CheckBox(name: "MyDictionary[ABC].Value", isChecked: Model.MyDictionary["ABC"], htmlAttributes: null)
If you need a checkbox, be sure to use Html.CheckBox instead of a standard HTML checkbox. The model will blow up if a value is not provided, and Html.CheckBox generates a hidden field to ensure a value is present when the checkbox is not checked.

Using Razor you can implement the for loop using a dictionary as follows without making changes to your object:
#foreach (var x in Model.Questions.Select((value,i)=>new { i, value }))
{
if (Model.Questions[x.i].QuestionType == "Single")
{
#Html.EditorFor(modelItem => (modelItem.Questions[x.i] as OpenDataPortal.ViewModels.SingleQuestionViewModel).AnswerText)
}
...
}
The collection needs to be either a List or Array for this to work.

I use this code maybe its can help
<input type="hidden" name="OffersCampaignDale[#(item.ID)].ID" value="#(item.ID)" />
#Html.Raw(Html.EditorFor(modelItem => item.NameDale, new { htmlAttributes = new { #class = "form-control" } })
.ToString().Replace("item.NameDale", "OffersCampaignDale[" + item.ID+ "].NameDale").Replace("item_NameDale", "NameDale-" + item.ID))
#Html.ValidationMessageFor(modelItem => item.NameDale, "", new { #class = "text-danger" })

Related

Null value in viewmodel after Post Action

I am getting null values in the controller http post part from the view model. All the values are null. I am not able to access the view model properties and select list values as well. How to solve the null values and access the selected city from the model for updating the database using db context.
I searched other similar questions but those results didnt help.
It will be of great help if anyone can solve the issue.
Model Class:
namespace MvcCoreAngular.ViewModels
{
public class DetailedResultEdit
{
public int employeeid { get; set; }
public string name { get; set; }
public List<SelectListItem> citieslist { get; set; }
public int cityid { get; set; }
public string department { get; set; }
public string gender { get; set; }
}
}
HTML:
#model IEnumerable<MvcCoreAngular.ViewModels.DetailedResultEdit>
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm("Edit", "Home", FormMethod.Post))
{
#foreach (var item in Model)
{
<table>
<tr>
#Html.Label("Name")
#Html.TextBoxFor(model => item.name)
<br />
</tr>
<tr>
#Html.Label("Department")
#Html.TextBoxFor(model => item.department)
<br />
</tr>
<tr>
#Html.Label("Cities")
#Html.DropDownListFor(model => item.cityid, item.citieslist, "", null)
<br />
</tr>
<tr>
<input type="submit" value="Submit" id="btnSubmit" />
</tr>
</table>
}
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(DetailedResultEdit mo)
{
//IEnumerable<tblcities> citieslist = from c in _context.tblcities.ToList<tblcities>().GroupBy(x=> x.cityname).Select(x=> x.First());
if (ModelState.IsValid) {
var empdata = _context.tblemployee.Find(mo.employeeid);
empdata.cityid = mo.cityid;
empdata.department = mo.department;
empdata.name = mo.name;
_context.SaveChanges();
}
Firstly,your code don't bind the data correctly,so the edit action cannot get the data.Besides,you didn't pass employeeid to action,so you can add a hidden input in the view,and then you can use _context.tblemployee.Find.
Here is a demo worked:
Controller:
[HttpGet]
public IActionResult Edit() {
List<tblemployee> tblemployees = _context.tblemployee.ToList();
List<DetailedResultEdit> detailedResultEdits = new List<DetailedResultEdit>();
List<SelectListItem> list = new List<SelectListItem> { new SelectListItem { Text = "NY", Value = "1" }, new SelectListItem { Text = "Boston", Value = "2" }, new SelectListItem { Text = "Dover", Value = "3" } };
foreach (tblemployee t in tblemployees) {
DetailedResultEdit temp = new DetailedResultEdit();
temp.cityid = t.cityid;
temp.name = t.name;
temp.employeeid = t.employeeid;
temp.department = t.department;
temp.gender = t.gender;
temp.citieslist = list;
detailedResultEdits.Add(temp);
}
return View(detailedResultEdits);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(DetailedResultEdit mo)
{
if (ModelState.IsValid)
{
var empdata = _context.tblemployee.Find(mo.employeeid);
empdata.cityid = mo.cityid;
empdata.department = mo.department;
empdata.name = mo.name;
_context.Attach(empdata).State = EntityState.Modified;
_context.SaveChanges();
Edit();
}
return View();
}
View:
#model IEnumerable<DetailedResultEdit>
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
#foreach (var item in Model)
{
#using (Html.BeginForm("Edit", "TestDB", FormMethod.Post))
{
<table>
<tr>
<input hidden name="employeeid" value="#item.employeeid" class="form-control" />
#Html.Label("Name")
<input name="name" value="#item.name" class="form-control" />
<br />
</tr>
<tr>
#Html.Label("Department")
<input name="department" value="#item.department" class="form-control" />
<br />
</tr>
<tr>
#Html.Label("Cities")
<select name="cityid"
asp-for="#item.cityid"
asp-items="#item.citieslist">
</select>
<br />
</tr>
<tr>
<input type="submit" value="Submit" id="btnSubmit" />
</tr>
</table>
}
}
tblemployee:
public class tblemployee
{
[Key]
public int employeeid { get; set; }
public string name { get; set; }
public int cityid { get; set; }
public string department { get; set; }
public string gender { get; set; }
}
result:

Get Null when Binding List of Object to Controller MVC Model

I am having trouble binding a model that contains list of objects for Editing method. This is the list of Factory which includes list of another object (FactoryHotline).
There is no problem when I get pass data from Controller to View. But when I try to send data from View back to Controller, some model's properties always null.
The Model is:
public class Factory
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<FactoryHotline> FactoryHotlineList { get; set; }
}
public class FactoryHotline
{
public Guid Id { get; set; }
public Guid FactoryId { get; set; }
public string Caption { get; set; }
public string Hotline { get; set; }
}
This is View:
#model List<WebDataLayer.Models.Factory>
<form action="/Factories/Edit" method="POST" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="form-horizontal">
<table id="factoriesTable">
<thead>
<tr>
<th>Name</th>
<th class="Hotline1" >Hotline 1</th>
<th class="Hotline2" >Hotline 2</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(model => model[i].Id)
<tr>
<td>#Model[i].Name</td>
#for (int h = 0; h < Model[i].FactoryHotlineList.Count; h++)
{
<td>
<div>
<b>Caption: </b>
#Html.EditorFor(model => model[i].FactoryHotlineList[h].Caption, new { htmlAttributes = new { #class = "form-control ShortInput", id = "captionInput", maxlength = "39" } })
</div>
<div>
<b>Hotline:</b>
#Html.EditorFor(model => model[i].FactoryHotlineList[h].Hotline, new { htmlAttributes = new { #class = "form-control ShortInput", id = "hotlineInput", maxlength = "15" } })
#Html.ValidationMessageFor(model => model[i].FactoryHotlineList[h].Hotline)
</div>
</td>
}
</tr>
}
</tbody>
</table>
</form>
In my controller the method for Edit is:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit (List<Factory> factories)
{
}
Only Id has value, the other(Caption, Hotline) are always null in List<Factory> factories
This is how I am passing Data from Controller to View
// GET: Edit
public ActionResult Edit()
{
var factories = _factoryService.All().OrderBy(p => p.Name);
var list = factories.ToList();
return View("Edit", list);
}
I works fine using Entity Framework.
That is because you have used HiddenFor to keep id as hidden field. To have the value in postback, it should be a part of input element(input,select,checkbox,textarea,etc) or as hidden field.
#Html.HiddenFor(model => model[i].Name)
I would suggest using a viewmodel along with automapper in this case.

complex type model wont pass list propery

hi guys i am having trouble with my mvc app. its a simple quiz app and i am stuck at creating create view for question model.
I have Question and Option model with appropriate view models(in my case they are QustionDTO and OptionDTO) and i want to make cshtml create view for Question with list of Options.like this but when i submit form, my list of options is null.
this is my Question and Option model
public class Question
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string QuestionText { get; set; }
public virtual ICollection<Option> Options { get; set; }
}
public class Option
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[Display(Name ="Answer text")]
public string OptionText { get; set; }
[Required]
public bool IsCorrect { get; set; }
}
this is my DTO models
public class QuestionDTO
{
public int Id { get; set; }
public string QuestionText { get; set; }
public List<OptionDTO> Options { get; set; }
}
public class OptionDTO
{
public int Id { get; set; }
public string OptionText { get; set; }
public bool IsCorrect { get; set; }
}
and this is my view with editor template located in "~/views/shared/editortemplate/OptionDTO.cshtml"
#model Quiz.BusinessEntites.QuestionDTO
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>QuestionDTO</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.QuestionText, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.QuestionText, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.QuestionText, "", new { #class = "text-danger" })
</div>
</div>
<table class="table" style="width:50%">
#for (int i = 0; i < 3; i++)
{
#Html.EditorFor(model=>model.Options[i])
}
</table>
<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>
this is OptionDTO editor template
#using Quiz.BusinessEntites
#model Quiz.BusinessEntites.OptionDTO
<tr>
<th class="col-md-2">
#Html.DisplayNameFor(m => m.OptionText)
</th>
<th class="col-md-2">
#Html.DisplayNameFor(m => m.IsCorrect)
</th>
</tr>
<tr>
<td class="col-md-2">
#Html.EditorFor(m => m.OptionText)
</td>
<td class="col-md-2">
#Html.EditorFor(m => m.IsCorrect)
</td>
</tr>
from the image above u can see that options list is null. if u have any suggestion it will be appreciated.
In your http post action method, the Bind attribute with Include list is telling the Model binder to bind only "Id","QuestionText" and "IsCorrect" properties of QuestionDto object from the posted form data. So the model binder will not bind the Options property value.
Remove the Bind attribute from your Http post action method.
There is no need to use the Bind attribute if your view model is specific to your view, means you have only properties needed for your view (In your case it looks like so)
public ActionResult Create(QuestionDTO model)
{
// to do :return something
}
If you want to use a non view specific view model, but still want to use Bind attribute to specify only subset of properties, Include just those properties. In your case, your code will be like
public ActionResult Create([Bind(Include="Id,QuestionText",Options"] QuestionDTO model)
{
// to do :return something
}
Also you should editer template view should be in a directory called EditorTemplates , not EditorTemplate

Passing values of checkboxes from View to Controller

I have a view with a number of checkboxes in it. I want to be able to pass the values of the checkboxes to the controller, then output a list of the OfficeNames that have been ticked. I am not sure how to pass the values of multiple checkboxes back to the controller, or how to output the OfficeNames based on which boxes have been ticked
View:
<p>
#using (Html.BeginForm())
{
<p>
Start Date: #Html.TextBox("StartDate") <br />
<br />
End Date: #Html.TextBox("EndDate") <br />
<br />
<input type="submit" value="Filter" />
</p>
}
<p>
#foreach (var item in Model.BettingOffices)
{
<label>#Html.DisplayFor(modelItem => item.OfficeName)</label>
<input type="checkbox" name="selectedShops" value="#item.OfficeName">
}
</p>
Controller:
public class DailyReportController : Controller
{
private RiskEntities _db = new RiskEntities();
// GET: /DailyReport/
public ActionResult Index(DateTime? startDate, DateTime? endDate)
{
if (startDate == null || endDate == null)
{
var dailyReportModelBlank = new DailyReportModel();
dailyReportModelBlank.BettingOffices = (from bo in _db.BettingOffices orderby bo.OfficeName select bo ).ToList();
//dailyReportModelBlank.DailyReports.Add(new DailyReport());
return View(dailyReportModelBlank);
}
var endDateToUse = (DateTime) endDate;
endDateToUse = endDateToUse.AddDays(+1);
var dailyReportModel = new DailyReportModel
{
DailyReports = (from dr in _db.DailyReports
where dr.DailyReportDate >= startDate
&& dr.DailyReportDate <= endDateToUse
select dr).ToList(),
BettingOffices = (from bo in _db.BettingOffices select bo).ToList()
};
return View(dailyReportModel);
}
Model:
public class DailyReportModel
{
private List<DailyReport> _dailyReports = new List<DailyReport>();
private List<BettingOffice> _bettingOffices = new List<BettingOffice>();
public List<DailyReport> DailyReports
{
get { return _dailyReports; }
set { _dailyReports = value; }
}
public List<BettingOffice> BettingOffices
{
get { return _bettingOffices; }
set { _bettingOffices = value; }
}
}
BettingOffice Class:
public partial class BettingOffice
{
public int BettingOfficeID { get; set; }
public string OfficeName { get; set; }
public string OfficeCode { get; set; }
public string IpAddress { get; set; }
public Nullable<bool> SupportOnly { get; set; }
public Nullable<int> SisSrNumer { get; set; }
public Nullable<bool> Local { get; set; }
public string Server { get; set; }
}
try this :
<p>
#using (Html.BeginForm())
{
<p>
Start Date: #Html.TextBox("StartDate")
<br />
<br />
End Date: #Html.TextBox("EndDate")
<br />
<br />
<input type="submit" value="Filter" />
</p>
}
</p>
<p>
#foreach (var item in Model.BettingOffices)
{
<label>#Html.DisplayFor(modelItem => item.OfficeName)</label>
<input type="checkbox" name="bettingOfficeIDs" value="#item.BettingOfficeID">
}
</p>
And in your Action you can get the selected office ids in bettingOfficeIDs variable:
public ActionResult YourActionName(int[] bettingOfficeIDs)
Few things that need to change here.
If you want values to be passed to action method they need to be within form not outside
For MVT to 'understand' checkbox values as array (or more complex object) you need to work with their html name attribute.
I will do demonstration application below that should help you understand how it works:
CsHtml: Notice that you need to add value attribute to checkboxes to be able to read their values, checkbox gets true only when checkbox is ticked and value is true, hence the javascript. You can add as many of complex object properties as hidden fields as long as you give them names that match to the object property names in viewModel. In this case I am only passing BettingOfficeID
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
$(document).on("click", "[type='checkbox']", function(e) {
if (this.checked) {
$(this).attr("value", "true");
} else {
$(this).attr("value","false");}
});
<p>
#using (Html.BeginForm())
{
<p>
Start Date: #Html.TextBox("StartDate") <br />
<br />
End Date: #Html.TextBox("EndDate") <br />
<br />
</p>
<p>
<input type="checkbox" name="BettingOffices[0].Selected" value="true">
<input type="hidden" name="BettingOffices[0].BettingOfficeID" value="1">
<input type="checkbox" name="BettingOffices[1].Selected" value="false">
<input type="hidden" name="BettingOffices[1].BettingOfficeID" value="2">
<input type="checkbox" name="BettingOffices[2].Selected" value="true">
<input type="hidden" name="BettingOffices[2].BettingOfficeID" value="3">
<input type="checkbox" name="BettingOffices[3].Selected" value="false">
<input type="hidden" name="BettingOffices[3].BettingOfficeID" value="4">
<input type="checkbox" name="BettingOffices[4].Selected" value="true">
<input type="hidden" name="BettingOffices[4].BettingOfficeID" value="5">
</p>
<input type="submit" value="submit"/>
}
Post Action method to add to controller
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(BettingViewModel viewModel)
{
return null;
}
BettingViewModel: I have added Selected property to BettingOffice class.
public class BettingViewModel
{
public string StartDate { get; set; }
public string EndDate { get; set; }
public List<BettingOffice> BettingOffices { get; set; }
}
public class BettingOffice
{
public bool Selected { get; set; }
public int BettingOfficeID { get; set; }
public string OfficeName { get; set; }
public string OfficeCode { get; set; }
public string IpAddress { get; set; }
public Nullable<bool> SupportOnly { get; set; }
public Nullable<int> SisSrNumer { get; set; }
public Nullable<bool> Local { get; set; }
public string Server { get; set; }
}
Hope this saves you some time.
View:
#using (Html.BeginForm("Createuser", "User", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<div class="form-group">
#Html.LabelFor(m => m.city, new { #class = "col-md-2 control-label" })
</div>
<div class="col-md-10">
<table>
<tr>
<td><input type="checkbox" name="city" value="Pune" id="1" />Pune</td>
<td><input type="checkbox" name="city" value="Banglore" id="2" />Banglore</td>
<td><input type="checkbox" name="city" value="Mumbai" id="3" />Mumbai</td>
</tr>
</table>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Create" />
</div>
</div>
}
[HttpPost]
public ActionResult Createuser(user user, string [] city)
{
var UserInfo = new user
{ Email =user.Email,Password=user.Password,Firstname=user.Firstname };
return View();
}
1. First of all, you are generating checkboxes with same name. So how you will be able to retrieve them on server end separately?
So declare some counter that gets incremented and name checkboxes uniquely.
#foreach (var item in Model.BettingOffices)
{
int counter=1;
var checkboxName = "selectedShops" + counter;
<label>#Html.DisplayFor(modelItem => item.OfficeName)</label>
<input type="checkbox" name="#checkboxName" value="#item.OfficeName">
counter++;
}
2. Now on submission of Form in your controller, get checkboxes as -
//Loop through the request.forms
for (var i = 0; i <= Request.Form.Count; i++)
{
var checkboxValue = Request.Form["selectedShops[" + i + "]"];
// Do whatever you want to with this checkbox value
}
For ticked values, you will probably get True value. Debug the retrieved value to write further code accordingly.
Try the following
your View is:
#foreach (var item in Model.BettingOffices)
{
<label>#Html.DisplayFor(modelItem => item.OfficeName)</label>
<input type="checkbox" name="selectedShops" value="#item.OfficeName">
}
Controller
[HttpPost]
public ActionResult Index(FormCollection collection)
{
if(!string.IsNullOrEmpty(collection["selectedShops"]))
{
string strSelectedShops = collection["selectedShops"];
}
}
Hi you can get the selected checkbox value using the bellow code it seem working fine fore me,
<script>
$(document).ready(function()
{
$("input[type=checkbox]").click(function()
{
var categoryVals = [];
categoryVals.push('');
$('#Category_category :checked').each(function() {
categoryVals.push($(this).val());
});
$.ajax({
type:"POST",
url:"<?php echo $this->createUrl('ads/searchresult'); ?>", //url of the action page
data:{'category': categoryVals},
success : function(response){
//code to do somethng if its success
}
});
}
}
</script>

How to pass list from view to controller

I have problem when pass a list in an object from view to controller, the list is always null. How should I do this?
My model:
public class ImageModel
{
public int id { get; set; }
public string url { get; set; }
public bool delete { get; set; }
}
public class SchoolImages
{
public Nullable<int> schoolid { get; set; }
public IList<ImageModel> images;
}
The view:
#model SchoolAppManager.Models.SchoolImages
#using (Html.BeginForm("DeleteImages", "Images"))
{
#Html.HiddenFor(x => x.schoolid)
<table>
#for (int i = 0; i < Model.images.Count(); i += 4) {
<tr>
<td>
<img src="#Url.Content(Model.images[i].url)" width="50%" />
<br />
#Html.CheckBoxFor(x => x.images[i].delete)
#Html.HiddenFor(x => x.images[i].id)
</td>
<td>
#if (i + 1 < Model.images.Count())
{
<img src="#Url.Content(Model.images[i + 1].url)" width="50%" />
<br />
#Html.CheckBoxFor(x => x.images[i + 1].delete)
#Html.HiddenFor(x => x.images[i + 1].id)
}
</td>
<td>
#if (i + 2 < Model.images.Count())
{
<img src="#Url.Content(Model.images[i + 2].url)" width="50%" />
<br />
#Html.CheckBoxFor(x => x.images[i + 2].delete)
#Html.HiddenFor(x => x.images[i + 2].id)
}
</td>
<td>
#if (i + 3 < Model.images.Count())
{
<img src="#Url.Content(Model.images[i + 3].url)" width="50%" />
<br />
#Html.CheckBoxFor(x => x.images[i + 3].delete)
#Html.HiddenFor(x => x.images[i + 3].id)
}
</td>
</tr>
}
</table>
<input type="submit" value="delete" />
}
When I click delete, SchoolImages is passed to the controller, SchoolImages.schoolId has value in the controller, however, SchoolImages.images is null. How can I pass SchoolImages.images to controller?
Default model binder doesn't work with fields, so make images a property:
public IList<ImageModel> images { get; set; }
I guess you will have problem binding complex types to your model. In case you don't get that working. Here is the alternative way.
You have a bunch of checkboxes, possibly with the same name and different values. You could post them to a method that takes a FormCollection, ie.
public ActionResult Test(FormCollection collection)
{
string results = collection["Blanks"];
}
This would give you a comma-delimited list of values (or null, where no checkboxes are ticked).
Alternatively, if you have the possible values as an array on the server then you could give the checkboxes names according to their array values, which would mean you could do something like this:
#using (Html.BeginForm("Test","Home"))
{
#Html.CheckBox("Blanks[0]", false);
#Html.CheckBox("Blanks[1]", false);
#Html.CheckBox("Blanks[2]", false);
<input type="submit" value="Submit" />
}
giving you an array of booleans in your Test method:
public ActionResult Test(bool[] Blanks)
{ }
Try changing your model "SchoolImages"; use array instead of IList<>.
It's null because the default model binder doesn't know how to initialize it.
Change your field images to be a property and add a constructor like this:
public class SchoolImages
{
public SchoolImages()
{
images = new List<ImageModel>();
}
public Nullable<int> schoolid { get; set; }
public IList<ImageModel> images { get; set; }
}
It should work.

Resources