MVC Enum Model Binding in For Loop - c#

I have an MVC 5 app where I am using a for loop so I can bind a collection when passing back to the controller. This works fine for all my properties except for the one that is based on a DropDownFor type.
The problem is the name of the property is not getting set to "product.[0].TypeOfSubscription.
I have tried 3 different ways: The first 2 method end up with a name of [0].TypeOfSubscription and the 3rd one does have the correct name product[0].TypeOfSubscription but there is no binding occuring when I pass it back to the controller.
I think the problem is that the 3rd option is binding but because it is hidden it is not getting the selected value assigned.
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription)
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription,
new { name = "product[" + #i + "].TypeOfSubscription"})
#Html.Hidden("product[" + #i + "].TypeOfSubscription",
Model[i].TypeOfSubscription)
Model
public class VmStoreProducts
{
public VmStoreProducts()
{
NoOfUsers = 1;
}
public enum SubscriptionType
{
Monthly,
Annual
}
public int MojitoProductId { get; set; }
[Display(Name = "Category")]
public string ProductCategory { get; set; }
public virtual string Name { get; set; }
public string Description { get; set; }
[Display(Name = "Image")]
public byte[] ImageData { get; set; }
[Display(Name = "Type of Subscription")]
public SubscriptionType TypeOfSubscription { get; set; }
public decimal Price { get; set; }
[Display(Name = "No. of Users")]
public int NoOfUsers { get; set; }
[Display(Name = "Total Price")]
[DisplayFormat(DataFormatString = "{0:C}")]
public decimal TotalPrice { get; set; }
}
For Loop - View
#model PagedList.IPagedList<VmStoreProducts>
#using Mojito.Domain
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Mojito Products</h2>
<div class="col-md-9"></div>
<div class="col-md-3">
#using (Html.BeginForm("Index", "MojitoProducts", FormMethod.Get))
{
<p>
#Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" />
</p>
}
</div>
#using (Html.BeginForm("AddToCart", "ShoppingCart", FormMethod.Post))
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().ImageData)
</th>
<th>
#Html.ActionLink("Category", "Index", new { sortOrder = ViewBag.SortByCategory, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Product", "Index", new { sortOrder = ViewBag.SortByProduct, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().Description)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().TypeOfSubscription)
</th>
<th>
#Html.ActionLink("Price", "Index", new { sortOrder = ViewBag.SortByPrice, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().NoOfUsers)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().TotalPrice)
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>
#if (Model[i].ImageData != null)
{
<div class="pull-left" style="margin-right: 10px">
<img class="img-thumbnail" width="75" height="75"
src="#Url.Action("GetImage", "MojitoProducts",
new { Model[i].MojitoProductId })" />
</div>
}
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].ProductCategory)
</td>
<td>
#Html.TextBox("product[" + #i + "].Name",
Model[i].Name, new { #readonly = "readonly" })
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].Description)
</td>
<td>
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription)
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription,
new { name = "product[" + #i + "].TypeOfSubscription"})
#Html.TextBox("product[" + #i + "].TypeOfSubscription",
Model[i].TypeOfSubscription, new { hidden=true })
</td>
<td>
#Html.TextBox("product[" + #i + "].Price",
Model[i].Price, new { #readonly = "readonly", style = "width:50px" })
</td>
<td>
#Html.TextBox("product[" + #i + "].NoOfUsers",
Model[i].NoOfUsers, new { type = "number", min = "0", style = "width:50px" })
</td>
<td>
#Html.TextBox("product[" + #i + "].TotalPrice",
Model[i].TotalPrice, new { style = "width:50px" })
</td>
<td>
<div class="pull-right">
#if (Request.Url != null)
{
#Html.Hidden("product[" + #i + "].MojitoProductId",
Model[i].MojitoProductId)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
}
</div>
</td>
</tr>
}
<tr>
<td colspan="6">
<div class="pull-right">
<input type="submit" class="btn btn-success" value="Add to cart" />
</div>
</td>
</tr>
</table>
}
Controller Method
public ActionResult AddToCart(List<VmStoreProducts> product, string returnUrl)
{
ShoppingCart cartObjects = (Session["CartObjects"] as ShoppingCart) ?? new ShoppingCart();
Session["CartObjects"] = cartObjects;
foreach (var item in product)
{
if (item.NoOfUsers > 0)
{
cartObjects.AddItem(item);
}
}
return RedirectToAction("Index", new { returnUrl });
}

Move the definition of the enum outside the VmStoreProducts class
public enum SubscriptionType
{
Monthly,
Annual
}
public class VmStoreProducts
{
public VmStoreProducts()
{
NoOfUsers = 1;
}
public int MojitoProductId { get; set; }
....
}
The for loop will name the selects
[0].TypeOfSubscription
[1].TypeOfSubscription
....
which will correctly bind on postback (assuming your action method is public ActionResult AddToCart(IEnumerable<VmStoreProducts> products) {...
Also, do not use
#Html.TextBox("product[" + #i + "].Name", Model[i].Name, new { #readonly = "readonly" })
Since you already using a DisplayFor for the same property a hidden input seems more appropriate, so
#Html.HiddenFor(m => m[i].Name)
or if you want to display it twice
#Html.TextBoxFor(m => m[i].Name, new { #readonly = "readonly" })
This applies to the other properties as well

Try using a textbox and hide it to persist the value or use another 'data- property

In case of DropDownListFor, when data is posted back to controller, selected value get lost, so we need to have a hidden textbox to keep the selected value

Related

Updates by partialview not affected to model

I have a problem with updating ViewModel by PartialView. PartialView includes Devices along with the location that varies depending on the DropDownList selected by the Customer. (At the bottom I present sample screenshot). The problem is that after accepting the submit button the property Devices in the ViewModel(FiscalizationViewModel) is not updating. Here are examples of models. I'm not sure I'm trying to solve this problem properly.
namespace TestMVC.ViewModels
{
public class FiscalizationViewModel
{
public int CustomerId { get; set; }
public string FiscalizationDate { get; set; }
public List<DevicesToFiscalizationViewModel> Devices { get; set; }
public FiscalizationViewModel()
{
Devices = new List<DevicesToFiscalizationViewModel>();
}
public IEnumerable<DevicesToLocalization> GetSelectedIds()
{
return (from d in Devices where d.Selected select new DevicesToLocalization() { DeviceId = d.DeviceId, LocalizationId = d.LocalizationId }).ToList();
}
}
public class DevicesToFiscalizationViewModel
{
public int DeviceId { get; set; }
public string DeviceName { get; set; }
public bool Selected { get; set; }
public string SerialNumber { get; set; }
public int LocalizationId { get; set; }
public IEnumerable<Localization> Localizations { get; set; }
public DevicesToFiscalizationViewModel()
{
Localizations = new List<Localization>();
}
}
}
Here is the method that is called by the Customer DropDownList event
public PartialViewResult CustomerChanged(int CustomerId)
{
var localizations = db.Localizations.Where(i => i.CustomerId == CustomerId).ToList();
var devicesToFsc = (from d in db.Devices
select new DevicesToFiscalizationViewModel()
{
DeviceId = d.DeviceId,
DeviceName = d.Name,
SerialNumber = d.SerialNumber,
}).ToList();
foreach (var item in devicesToFsc)
{
item.Localizations = localizations;
}
return PartialView("~/Views/Fiscalizations/EditorTemplates/DevicesToFiscalizationViewModel.cshtml", devicesToFsc);
//--------------------------------
$("#customerChanged").on("change", function () {
$.ajax(
{
url: '/Fiscalizations/CustomerChanged?CustomerId=' + $(this).val(),
type: 'GET',
data: "",
contentType: 'application/json; charset=utf-8',
success: function (data) {
$("#devicesToFiscalization").html(data);
}
});
});
This is little partial of Views (Fiscalization create view)
#model TestMVC.ViewModels.FiscalizationViewModel
<table class="table" id="devicesToFiscalization">
<thead>
...
</thead>
#Html.Partial("~/Views/Fiscalizations/EditorTemplates/DevicesToFiscalizationViewModel.cshtml", Model.Devices)
</table>
PartialView:
#model IEnumerable<TestMVC.ViewModels.DevicesToFiscalizationViewModel>
#foreach(var item in Model)
{
<tbody>
<tr>
<td style="text-align:center">
<div class="checkbox">
#Html.EditorFor(m => item.Selected)
</div>
</td>
<td>
#Html.DisplayFor(m => item.DeviceName)
</td>
<td>
#Html.DisplayFor(m => item.SerialNumber)
</td>
<td>
#Html.DropDownList("LocalizationId", new SelectList(item.Localizations, "LocalizationId", "Name"), "Select", htmlAttributes: new { #class = "form-control", style = "width: 200px;" })
</td>
<td>
#Html.HiddenFor(m => item.DeviceId)
</td>
</tr>
</tbody>
Here is a screenshot of how it looks
click
and here is screenshot from debugger with bad result
bad
Based on my understating from your views, your issues is using different models for main view and partial view. You should use exactly the same model in both the model binding could update the model on server side. keep both models TestMVC.ViewModels.FiscalizationViewModel or IEnumerable<TestMVC.ViewModels.DevicesToFiscalizationViewModel>
It works :) Below I show how it looks after changes
main view:
#model TestMVC.ViewModels.FiscalizationViewModel
<div id="devicesToFiscalization">
#Html.Partial("~/Views/Fiscalizations/EditorTemplates/DevicesToFiscalizationViewModel.cshtml", Model)
</div>
Partial view:
#model TestMVC.ViewModels.FiscalizationViewModel
<table class="table">
<thead>
<tr>
<th>
Select
</th>
<th>
Name
</th>
<th>
Serial number
</th>
<th>
Localization
</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Devices.Count; i++)
{
<tr>
<td style="text-align:center">
<div class="checkbox">
#Html.EditorFor(m => m.Devices[i].Selected)
</div>
</td>
<td>
#Html.DisplayFor(m => m.Devices[i].DeviceName)
</td>
<td>
#Html.DisplayFor(m => m.Devices[i].SerialNumber)
</td>
<td>
#Html.DropDownListFor(m => m.Devices[i].LocalizationId, new SelectList(Model.Devices[i].Localizations, "LocalizationId", "Name"), "Select", htmlAttributes: new { #class = "form-control", style = "width: 200px;" })
</td>
<td>
#Html.HiddenFor(m => m.Devices[i].DeviceId)
</td>
</tr>
}
</tbody>
and CustomerChanged method:
public PartialViewResult CustomerChanged(int CustomerId)
{
var localizations = db.Localizations.Where(i => i.CustomerId == CustomerId).ToList();
var Devices = (from d in db.Devices
select new DevicesToFiscalizationViewModel()
{
DeviceId = d.DeviceId,
DeviceName = d.Name,
SerialNumber = d.SerialNumber,
}).ToList();
foreach (var item in Devices)
{
item.Localizations = localizations;
}
var fsc = new FiscalizationViewModel();
fsc.Devices = Devices;
return PartialView("~/Views/Fiscalizations/EditorTemplates/DevicesToFiscalizationViewModel.cshtml", fsc);
}
========================================================================
I'm trying to write this using EditorFor but I have a problem with correctly writing the CustomerChanged method that returns a list of Devices and not expecting this EditorTemplate that looks as follows:
#model TestMVC.ViewModels.DevicesToFiscalizationViewModel
<tr>
<td style="text-align:center">
<div class="checkbox">
#Html.EditorFor(m => m.Selected)
</div>
</td>
<td>
#Html.DisplayFor(m => m.DeviceName)
</td>
<td>
#Html.DisplayFor(m => m.SerialNumber)
</td>
<td>
#Html.DropDownListFor(m => m.LocalizationId, new SelectList(Model.Localizations, "LocalizationId", "Name"), "Select", htmlAttributes: new { #class = "form-control", style = "width: 200px;" })
</td>
<td>
#Html.HiddenFor(m => m.DeviceId)
</td>
</tr>
Main View:
<table class="table" id="devicesToFiscalization">
...
<tbody>
#Html.EditorFor(m => m.Devices)
</tbody>
</table>

How to put two models in one view [duplicate]

This question already has answers here:
Two models in one view in ASP MVC 3
(12 answers)
Closed 6 years ago.
How can I put two models in one view. Im just new so thats why I cant understand some other answers about this question. Help me please. thank you very much for understanding. I need to finish it in time.
VIEW
#model IEnumerable, PagedList.IPagedLis<ARM2.Models.Institution>
#model PagedList.IPagedList<ARM2.Models.Institution>,
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Insitution";
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
<div class="container-fluid" id="page-content-wrapper">
<h2>INSTITUTION MANAGEMENT</h2>
<br />
<div class="panel panel-default">
<div class="panel-heading">List of Institutions</div>
<div class="panel-body">
<button type="button" class="btn btn-primary pull-right btn-sm" data-toggle="modal" data- target="#addInstitutionModal"> Add &nbsp ; </button>
<br /><br />
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm("Index", "Insitution", FormMethod.Get))
{
<p>
Find by name: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" />
</p>
}
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.InstitutionID)
</th>
<th>
#Html.ActionLink("Institution Name", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.IIN)
</th>
<th>
#Html.ActionLink("Date Added", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
Action
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.InstitutionID)
</td>
<td>
#Html.DisplayFor(modelItem => item.InstitutionName)
</td>
<td>
#Html.DisplayFor(modelItem => item.IIN)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateAdded)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.InstitutionID }) |
#Html.ActionLink("Details", "Details", new { id=item.InstitutionID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.InstitutionID })
</td>
</tr>
}
</table>
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
</div>
</div>
CONTROLLER
namespace ARM2.Controllers
{
public class InstitutionsController : Controller
{
private InstitutionDBContext db = new InstitutionDBContext();
// GET: Institutions
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.IDParm = String.IsNullOrEmpty(sortOrder) ? "ID_desc" : "";
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = searchString;
var insti = from s in db.institutions
select s;
if (!String.IsNullOrEmpty(searchString))
{
insti = insti.Where(s => s.InstitutionName.Contains(searchString));
}
switch (sortOrder)
{
case "ID_desc":
insti = insti.OrderByDescending(s => s.InstitutionID);
break;
case "name_desc":
insti = insti.OrderByDescending(s => s.InstitutionName);
break;
case "Date":
insti = insti.OrderBy(s => s.DateAdded);
break;
case "date_desc":
insti = insti.OrderByDescending(s => s.DateAdded);
break;
default:
insti = insti.OrderBy(s => s.InstitutionID);
break;
}
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(insti.ToPagedList(pageNumber, pageSize));
}
MODEL
namespace ARM2.Models
{
public class Institution
{
public int InstitutionID { get; set; }
public string InstitutionName { get; set; }
public int IIN { get; set; }
public DateTime DateAdded { get; set; }
}
public class InstitutionDBContext : DbContext
{
public DbSet<Institution> institutions { get; set; }
}
}
This is not possible. You should create a ViewModel that includes both these models.

sending values to url string on dropdown selected value change in asp.net MVC

I have two tables. First is Development region and second is Zone. Zone has got RegionID as a foreign key. I would like to populate all the row from Zone table that is related with the Region selected from the dropdown list. I cannot figure out why the value is not being passed in url string. Please help me out and suggest the best way to accomplish it. Below are the models, controllers and view.
Model Zone
public class Zone
{
[Key]
public int ZoneID { get; set; }
[Required]
[Display(Name = "Zone Code")]
[RegularExpression(#"^[a-zA-Z]*$"), StringLength(5, ErrorMessage = "Code cannot be more than 5 charachter long")]
[Column("ZCode")]
public string ZoneCode { get; set; }
[Display(Name ="Zone"),RegularExpression(#"^[A-Z]+[a-z]*$"),Required]
public string ZoneName { get; set; }
public int RegionID { get; set; }
public virtual DevRegion devregion { get; set; }
[Required]
[Display(Name ="Active")]
public Boolean isActive { get; set; }
}
Model DevRegions
public class DevRegion
{
[Key]
public int RegionID { get; set; }
[Required]
[Display(Name = "Code")]
[RegularExpression(#"^[a-zA-Z]*$"), StringLength(5, ErrorMessage = "Code cannot be more than 5 charachter long")]
[Column("RCode")]
public string RegionCode { get; set; }
[Required]
[Display(Name ="Region")]
[Column("RName")]
[RegularExpression(#"^[A-Z]+[a-zA-Z\s-]*$", ErrorMessage ="Region can only consist of alphabets, space and dash")]
[StringLength(30,ErrorMessage ="Region cannot exceed 30 characters")]
public string RegionName { get; set; }
[Required]
[Display(Name ="Active")]
public Boolean isActive { get; set; }
}
ZonesController
public class ZonesController : Controller
{
private HuRISContext db = new HuRISContext();
// GET: Zones
public ActionResult Index(int? id)
{
ViewBag.RegionID = new SelectList(db.DevRegions, "RegionID", "RegionName");
var zones = db.Zones.Include(z => z.devregion).Where(x=>x.RegionID==(int)(id??x.RegionID));
return View(zones.ToList());
}
Index.cshtml
#model IEnumerable<HuRIS.Models.Zone>
....
<p>#Html.ActionLink("Create New", "Create")</p>
#using (Html.BeginForm("Index","Zones",FormMethod.Get))
{
#Html.AntiForgeryToken();
<div class="panel panel-info">
<div class="panel-body">
<div class="form-group center-block">
<label for="RegionID" class="control-label">Region:</label>
#Html.DropDownList("RegionID", null, "Show all Zones", htmlAttributes: new { #class = "form-control", #onchange = "this.form.submit();" })
</div>
</div>
</div>
}
<table class="table">
<tr>
<th>#Html.DisplayNameFor(model => model.devregion.RegionName)</th>
<th>#Html.DisplayNameFor(model => model.ZoneCode)</th>
<th>#Html.DisplayNameFor(model => model.ZoneName)</th>
<th>#Html.DisplayNameFor(model => model.isActive)</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.devregion.RegionName</td>
<td>#Html.DisplayFor(modelItem => item.ZoneCode)</td>
<td>#Html.DisplayFor(modelItem => item.ZoneName)</td>
<td>#Html.DisplayFor(modelItem => item.isActive)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ZoneID }) |
#Html.ActionLink("Details", "Details", new { id = item.ZoneID }) | #Html.ActionLink("Delete", "Delete", new { id = item.ZoneID })
</td>
</tr>
}
</table>
JQuery
$(document).ready(function () {
$(".form-control").change(function () {
$.ajax({
url: "~/ZonesController/Index",
type: 'GET',
cache: false,
data: { RegionID: $(".form-control").val() },
success: function (data) {
}
});
});
});
index method as shown below
public ActionResult Index()
{
ViewBag.Region = new SelectList(db.DevRegions, "RegionID", "RegionName");
var allzones = db.Zones.Include(z => z.devregion);
return View(allzones.ToList());
}
create new method as Shown below to accept the id selected on dropdown change event and create the partial view to load on the list of data from the table depending on what is selected on the dropdown:
public ActionResult ZoneList(int? id)
{
var zones = db.Zones.Include(z => z.devregion).Where(x => x.RegionID == (int)(id ?? x.RegionID));
return PartialView("~/Views/PartialViews/_ZoneList.cshtml", zones.ToList());
}
changed javascript as follows.
$("#Region").change(function () {
var selectedID = $(this).val();
$.get('/Zones/ZoneList/' + selectedID, function (data) {
$('.table').html(data);
//$('.table').fadeOut("linear");
//$('.table').fadeIn("linear");
});
});
});
on the index.cshtml changed the code as follows:
#model IEnumerable<HuRIS.Models.Zone>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken();
<div class="panel panel-info">
<div class="panel-body">
<div class="form-group center-block">
<label for="RegionID" class="control-label">Region:</label>
#Html.DropDownList("Region", null, "Show all Zones", htmlAttributes: new { #class = "form-control"})
</div>
</div>
</div>
}
#{
Html.RenderPartial("~/Views/PartialViews/_ZoneList.cshtml", Model);
}
partial view _ZoneList.cshtml
#model IEnumerable<HuRIS.Models.Zone>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.devregion.RegionName)
</th>
<th>
#Html.DisplayNameFor(model => model.ZoneCode)
</th>
<th>
#Html.DisplayNameFor(model => model.ZoneName)
</th>
<th>
#Html.DisplayNameFor(model => model.isActive)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.devregion.RegionName)
</td>
<td>
#Html.DisplayFor(modelItem => item.ZoneCode)
</td>
<td>
#Html.DisplayFor(modelItem => item.ZoneName)
</td>
<td>
#Html.DisplayFor(modelItem => item.isActive)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ZoneID }) |
#Html.ActionLink("Details", "Details", new { id = item.ZoneID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ZoneID })
</td>
</tr>
}

How to bind dropdown list in edit page use of for loop in asp.net mvc [duplicate]

This question already has answers here:
MVC5 Razor html.dropdownlistfor set selected when value is in array
(3 answers)
Closed 5 years ago.
I was writing different type of code from Google but it is not display correct value in the dropdown. It shows the correct value in the textbox but not selected value in the dropdown.
Model
public Int64 EvaluationInfoID { get; set; }
public Int64 EvalCategoryID { get; set; }
public string EvalCategoryName { get; set; }
public string EvalCategoryDesc { get; set; }
public Int64 UserID { get; set; }
public DateTime? EvaluationDate { get; set; }
public int EvalTypeID { get; set; }
Controller
var models = new List<EvaluationInfoViewModel>();
ViewBag.GridState = this.GridRouteValues();
string serachCriteria = string.Format("created_by={0} and to_date(to_char(evaldate,'MM/DD/YYYY'),'MM/DD/YYYY')={1} ", Convert.ToInt32(Session["UserID"]), "to_date('" + evaldate.ToShortDateString() + "','MM/DD/YYYY')");
PODService.EvaluationInfo[] getData = service.GetEvaluationInfoBySearchCriteria(serachCriteria);
PODService.EvaluationCategory[] evalcat = service.GetEvalCategoryBySearchCriteria(" EC.Eval_ID= 1");//150811VP: For Self Evaluation Eval_ID=1
PODService.EvaluationType[] evalTypes = service.GetEvaluationTypeList();
ViewData["EVALTYPE"] = new SelectList(evalTypes, "EvaluationType_ID", "EvaluationType_Name");
for (var i = 0; i < getData.Length; i++)
{
models.Add(new EvaluationInfoViewModel());
}
for (var i = 0; i < models.Count; i++)
{
string serachCriteria1 = string.Format("created_by={0} and to_date(to_char(evaldate,'MM/DD/YYYY'),'MM/DD/YYYY')={1} ", Convert.ToInt32(Session["UserID"]), "to_date('" + evaldate.ToShortDateString() + "','MM/DD/YYYY')");
models[i].EvalCategoryID = getData[i].EvalCategory_ID;
models[i].EvalCategoryName = getData[i].EvalCategoryName;
//models[i].EvalCategoryDesc = getData[i].Eval_CategoryDescription;
models[i].UserID = Convert.ToInt64(Session["UserID"]);
models[i].EvaluationDate = getData[i].EvaluationDate;
models[i].EvalTypeID = getData[i].EvalTypeID;
ViewData["EVALTYPEInfo"] = new SelectList(evalTypes, "EvaluationType_ID", "EvaluationType_Name", models[i].EvalTypeID);
View
#model List<PODWeb.Models.EvaluationInfoViewModel>
#{
Layout = null;
}
#using (Html.BeginForm("EditEvaluationInfo", "EvaluationInfo", FormMethod.Post))
{
<table border="1px" style="margin-left: 122px">
<tr>
<td>
<table>
#for (var i = 0; i < Model.Count(); i++)
{
#Html.HiddenFor(m=>m[i].UserID)
#Html.HiddenFor(m=>m[i].EvaluationDate)
#Html.HiddenFor(m =>m[i].EvalTypeID)
<tr>
<td>
#Model[i].EvalCategoryName
#Html.EditorFor(m =>m[i].EvalTypeID)
</td>
<td>
#*#Html.DropDownListFor(m => m[i].EvalTypeID, ViewData["EVALTYPEInfo"] as IEnumerable<SelectListItem>, "Select Rating", new { #style = "width:200px" })*#
</td>
</tr>
<tr>
<td>
#Model[i].EvalCategoryDesc
#Html.HiddenFor(m => m[i].EvalCategoryID)
</td>
<td>
</td>
</tr>
<tr>
<td colspan="2">
<hr />
</td>
</tr>
}
<tr>
<td>
<input type="submit" name="Save" value="Save" class="t-button" style="margin-left: 471px" />
</td>
</tr>
</table>
</td>
</tr>
</table>
}
I want to display selected evaltypeid in dropdownlist but it is not displaying.
You have the code for the dropdown list commented out:
#*#Html.DropDownListFor(m => m[i].EvalTypeID,
ViewData["EVALTYPEInfo"] as IEnumerable<SelectListItem>,
"Select Rating", new { #style = "width:200px" })*#
You need to remove the outer #* and *#
#Html.DropDownListFor(m => m[i].EvalTypeID,
ViewData["EVALTYPEInfo"] as IEnumerable<SelectListItem>,
"Select Rating", new { #style = "width:200px" })
Also delete the #Html.EditorFor(m =>m[i].EvalTypeID) from your code.

Null values in HTML form from MVC view

I would like to save users steps and have each row in my MVC index view be a form.
I am using the HTML.Begin form inside the foreach to build the individual forms. The page renders without errors and the form submits without problems, but I can not bind to a model inside the controller - thus all the submitted data is lost.
I have validated that the form values are there to begin with when the form is submitted: item.Completed=true&item.Completed=false&item.Comment=HELLO+WORLD+&item.FinalizeStepId=1&item.StepId=1, but the controller does not accept them and the FinalizeStepViewModel object is created with null values.
So how do I get the form to pass back the data correctly?
This might be my second question ever on Stackoverflow, so let me know what additional information I might need to add.
Thanks.
=== Model =====
public class FinalizeStepViewModel
{
public int FinalizeStepId { get; set; }
// foreign key from Step table
public int StepId { get; set; }
// name of taks from Step table
public string StepDesc { get; set; }
[DisplayName("Review Data")]
public string ReviewFormulaValue { get; set; }
[Required]
public bool Completed { get; set; }
[DisplayName("Fiscal Year")]
public int FiscalYear { get; set; }
// Period for the adjustment
[Required]
public int Period { get; set; }
[Required]
public string UserID { get; set; }
[Required]
[DisplayName("Created By")]
public string CreatedBy { get; set; }
[Required]
[DisplayName("Created At")]
public DateTime CreatedAt { get; set; }
public string Comment { get; set; }
==== View ==========
#model IEnumerable
#{
ViewBag.Title = "Index";
// is everything completed, if yes => enabled
string alldone = "enabled";
}
<h2>Finalize Checklist</h2>
<table class="table">
<tr>
<th>
Completed
</th>
<th>
Finalized Task
</th>
<th>
Review Data
</th>
<th>
#Html.DisplayNameFor(model => model.Comment)
</th>
<th></th>
<th></th>
#*<th>
#Html.DisplayNameFor(model => model.FiscalYear)
</th>
<th>
#Html.DisplayNameFor(model => model.Period)
</th>
<th>
#Html.DisplayNameFor(model => model.CreatedBy)
</th>
<th>
#Html.DisplayNameFor(model => model.CreatedAt)
</th>
<th>
#Html.DisplayNameFor(model => model.UserID)
</th>*#
<th></th>
</tr>
#foreach (var item in Model)
{
//<form action="/FinalizeSteps/Checklist/" method="post">
//#using (Html.BeginForm("Login", "Account", FormMethod.Post))
//// <form action="/Account/Login" action="post">
using (Html.BeginForm("EditFromChecklist", "FinalizeSteps", FormMethod.Post, new { finalizeStepPassed = Model }))
{
<tr>
<td>
<div class="form-group" style="text-align: center; vertical-align: text-top;">
<div class="checkbox">
#Html.EditorFor(modelItem => item.Completed)
#if (item.Completed == false) { alldone = "disabled"; }
</div>
</div>
</td>
<td>
<h4>#Html.DisplayFor(modelItem => item.StepDesc)</h4>
</td>
<td style="text-align: center;">
#Html.DisplayFor(modelItem => item.ReviewFormulaValue)
</td>
<td>
<div class="form-group" style="width: 300px;">
#Html.EditorFor(modelItem => item.Comment, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(modelItem => item.Comment, "", new { #class = "text-danger" })
</div>
</td>
<td>
<div class="form-group">
#Html.EditorFor(modelItem => item.FinalizeStepId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(modelItem => item.FinalizeStepId, "", new { #class = "text-danger" })
</div>
</td>
<td>
<div class="form-group">
#Html.EditorFor(modelItem => item.StepId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(modelItem => item.FinalizeStepId, "", new { #class = "text-danger" })
</div>
</td>
#*<td>
#Html.DisplayFor(modelItem => item.FiscalYear)
</td>
<td>
#Html.DisplayFor(modelItem => item.Period)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreatedBy)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreatedAt)
</td>
<td>
#Html.DisplayFor(modelItem => item.UserID)
</td>*#
<td>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
#Html.ActionLink("Save", "EditFromChecklist", new { FinalizeStepId = item.FinalizeStepId, StepId = item.StepId, Completed = item.Completed, Comment = item.Comment })
#*#Html.ActionLink("Edit", "Edit", new { id = item.FinalizeStepId }) |
#Html.ActionLink("Details", "Details", new { id = item.FinalizeStepId }) |
#Html.ActionLink("Delete", "Delete", new { id = item.FinalizeStepId })*#
</td>
</tr>
}
}
</table>
=== Controller Method ====
[HttpPost]
public ActionResult EditFromChecklist([Bind(Include = "FinalizeStepId,StepId,Completed,Comment")] FinalizeStepViewModel finalizeStepPassed)
{
// Do we have a FinalizeStepId?
if (finalizeStepPassed.FinalizeStepId != 0)
{
// Yes, this is an edit
...
Change your EditFromChecklist action's parameter from finalizeStepPassed to item.
Or you could use a partial view to submit your data.
_FinalizeStepPartial.cshtml
#model FinalizeStepViewModel
using (Html.BeginForm("EditFromChecklist", "FinalizeSteps"))
{
#Html.EditorFor(model => model.Completed)
// rest of your form
}
and in the main view inside of loop call the partial
#foreach (var item in Model)
{
#Html.Partial("_FinalizeStepPartial",item)
}
You should bind to a IList instead of IEnumerable, and instead of
#foreach (var item in Model)
{
#Html.EditorFor(modelItem => item.Completed)
}
Use this syntax
#for( int i=0; i < Model.Count; i++ )
{
#Html.EditorFor(modelItem => Model[i].Completed)
}
Here is an earlier topic that also discussed this: How to pass IEnumerable list to controller in MVC including checkbox state?

Categories

Resources