How to send IEnumerable back from View to Controller - c#

I'm pretty new to MVC and ASP.Net, my controller has 2 create methods for GET and POST. Through the Get method I'm generating a list and sending it into the view. In the view I'm making changes to a specific value in each var in the list and trying to send it back to the controller and the POST method.
When reaching the Post method, the value of the list is null.
The list I'm sending is a list of products and I'm using a view model to create a class with common values to pass through to the view.
To pass through the IEnumerable collection that was edited by the view I tried using BeginCollectionForm, setting the items through ViewBag, make changes to the model (#model IEnumerable<MarsBurgerV1.ViewModel.ItemVM>), but still each time the checkout button is being pressed the list in the Post method is NULL.
After a lot of tries and changes, currently my code looks as the following:
OrderController.cs (relevant parts)
public class OrderController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
public ActionResult Create()
{
var meals = (from m in db.meals
select new ItemVM
{
Id = m.Id,
Name = m.Name,
Price = m.Price,
ItemType = "Meal",
ImageURL = m.ImageUrl,
Quantity = 0
}).ToList();
var drinks = (from d in db.drinks
select new ItemVM
{
Id = d.Id,
Name = d.Name,
Price = d.Price,
ItemType = "Drink",
Quantity = 0
}).ToList();
//More Like That....
List<ItemVM> items = new List<ItemVM>();
items.AddRange(meals);
items.AddRange(drinks);//More Like...
return View(items.ToList());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IEnumerable<ItemVM> items = null)
{
//Here items equals to null.
if (ModelState.IsValid)
{
//.....
}
return View();
}
Views/Order/Create.cshtml:
#model IEnumerable<***.ViewModel.ItemVM>
#{
ViewBag.Title = "Create";
var lst = Model.ToList();
ViewBag.List = Model.ToList();
}
<style>
tr td {
vertical-align: middle;
}
</style>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h3> Order:</h3>
<table class="table table-condensed table-hover">
<tr calss="table-header">
<th>
#Html.DisplayName("Preview")
</th>
<th>
#Html.DisplayNameFor(m => m.Name)
</th>
<th>
#Html.DisplayNameFor(m => m.Price)
</th>
<th>
#Html.DisplayName("Quantity")
</th>
<th></th>
<th></th>
</tr>
#for (var i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#if (Model.ElementAt(i).ImageURL != null)
{
<img src="#Url.Content(Model.ElementAt(i).ImageURL)" alt="IMAGES" height="100" width="100" />
}
</td>
<td>
#Html.DisplayFor(m => Model.ElementAt(i).Name)
</td>
<td>
#Html.DisplayFor(m => Model.ElementAt(i).Price)
</td>
<td>
<a type="button" class="btn btn-danger btn-xs" href="#">
<span class="glyphicon glyphicon-minus"></span>
</a>
#Html.EditorFor(l => lst[i].Quantity, new { htmlattribute = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => lst[i].Quantity, "", new { #class = "text-danger" })
<a type="button" class="btn btn-success btn-xs" id="plus" href="#">
<span class="glyphicon glyphicon-plus"></span>
</a>
</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Checkout" class="btn btn-primary"/>
</div>
</div>
}
ViewModel/ItemVM.cs:
namespace ***.ViewModel
{
public class ItemVM
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
public double Price { get; set; }
[Required]
public string ItemType { get; set; }
public string ImageURL { get; set; }
[Required]
public int Quantity { get; set; }
}
}
In the end I want to use the "Create" (HttpPost method) to create a new order based on the values in the list received from the view.
What is the proper way of doing that and receiving the IEnumerable into the POST method?

Ok, I was finally able to make it work.
I've changed the #model to List Type,
Add the (actionName, Controller, FormMethod) to the HTML Helper Html.BeginForm,
Used Model[i] inside the loop to access variables and
marked all unchanged variables with
#Html.HiddenFor.
Create.cshtml:
#model List<MarsBurgerV1.ViewModel.ItemVM>
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm("Create","Order", FormMethod.Post))
{
#Html.AntiForgeryToken()
<h3> Order:</h3>
<table class="table table-condensed table-hover">
<tr calss="table-header">
<th>
#Html.DisplayName("Preview")
</th>
<th>
#Html.DisplayName("Name")
</th>
<th>
#Html.DisplayName("Price")
</th>
<th>
#Html.DisplayName("Quantity")
</th>
<th></th>
<th></th>
</tr>
#for (var i = 0; i < Model.Count(); i++)
{
<tr>
#Html.HiddenFor(m => Model[i].Id)
#Html.HiddenFor(m => Model[i].Type)
<td>
#Html.HiddenFor(m => Model[i].ImageURL)
#if (Model[i].ImageURL != null)
{
<img src="#Url.Content(Model[i].ImageURL)" alt="IMAGES" height="100" width="100" />
}
#Html.ValidationMessageFor(model => Model[i].ImageURL, "", new { #class = "label-control" })
</td>
<td>
#Html.HiddenFor(m => Model[i].Name)
#Html.DisplayFor(m => Model[i].Name)
#Html.ValidationMessageFor(model => Model[i].Name, "", new { #class = "label-control" })
</td>
<td>
#Html.HiddenFor(m => Model[i].Price)
#Html.DisplayFor(m => Model[i].Price, new { #class = "form-control" })
#Html.ValidationMessageFor(model => Model[i].Price, "", new { #class = "label-control" })
</td>
<td>
<a type="button" class="btn btn-danger btn-xs" href="#">
<span class="glyphicon glyphicon-minus"></span>
</a>
#Html.EditorFor(model => Model[i].Quantity, new { htmlattribute = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => Model[i].Quantity, "", new { #class = "text-danger" })
<a type="button" class="btn btn-success btn-xs" id="plus" href="#">
<span class="glyphicon glyphicon-plus"></span>
</a>
</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" value="Checkout" class="btn btn-primary"/>
</div>
</div>
}
Thanks Everyone for the help.

Related

How to pass List<Model> from view to controller [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 4 years ago.
Being a newbie in ASP.NET MVC framework, I am stack in sending a list of my model back to the controller via POST method. Below are samples of my source code and their explanation.
Model Class:
public class SiteIdentifier
{
[Display(Name = "Configuration Id")]
public string ConfigurationId { get; set; }
[Display(Name = "County")]
public string County { get; set; }
}
Controller (Get Method):
public ViewResult ViewNewSites()
{
List<SiteIdentifier> sites = new List<SiteIdentifier>()
{
new SiteIdentifier{ConfigurationId = 1, County = "County1"},
new SiteIdentifier{ConfigurationId = 2, County = "County2"},
new SiteIdentifier{ConfigurationId = 3, County = "County3"}
};
return View(sites);
}
View:
In this view, the user has to select some rows using checkbox and click on the submit button and the submit button has to pass those checked rows to controller.
#using HIE_Management_Studio.Common
#model IEnumerable<SiteIdentifier>
<!--If there is nothing to show, do not render this place.-->
#if (Model != null)
{
using (Html.BeginForm("CopyToProductionPOST", "CopyBySite",
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
}))
{
<div class="row">
<div class="col-md-12">
<div class="alert alert-info">
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>
<input type="checkbox" id="chkSelectAll" />
</th>
<th>
#Html.DisplayNameFor(model => model.ConfigurationId)
</th>
<th>
#Html.DisplayNameFor(model => model.County)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td class="text-nowrap">
#Html.CheckBoxFor(modelItem => item.Selected, new { #class = "chkSelect" })
</td>
<td>
#Html.EditorFor(modelItem => item.ConfigurationId)
#Html.HiddenFor(modelItem => item.ConfigurationId)
</td>
<td>
#Html.EditorFor(modelItem => item.County)
#Html.HiddenFor(modelItem => item.County)
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-md-12">
<input type="submit" value="Submit" class="btn btn-info" />
</div>
</div>
<script>
$("#chkSelectAll").bind("change", function () {
$(".chkSelect").prop("checked", $(this).prop("checked"));
});
$(".chkSelect").bind("change", function () {
if (!$(this).prop("checked"))
$("#chkSelectAll").prop("checked", false);
});
$(".alert").hide().fadeIn("slow");
</script>
}
}
Controller (Post Method)
Now here is the post method in my controller that has to get all the selected rows from the view.
[HttpPost]
public ViewResult CopyToProductionPOST(List<SiteIdentifier> formCollection)
{
SiteIdentifier siteIdentifier = new SiteIdentifier();
// siteIdentifier.ConfigurationId = formCollection[0]["ConfigurationId"];
return View("CopyBySite");
}
I tried below link and it worked :)
https://www.c-sharpcorner.com/article/pass-dynamically-added-html-table-records-list-to-controller/

Cannot get the Partialview Model in Parent Controller

I am creating a DataEntry Screen which have a three dropdownlist at the top
which is cascaded using ajax . And A partial view is also rendered using Ajax which will show all the items against that selection user made on the dropdowns. The partialview consist of a table with multiple rolls.
I am not able to get the collection of data selected by the user in the partial view (table )in my controller.
My Controller
[HttpGet]
public ActionResult ApproveLaysheet()
{
LaySheetShortageViewModel mdl = new LaySheetShortageViewModel();
ViewBag.AtcID = new SelectList(db.AtcMasters.Where(o => o.IsClosed == "N"), "AtcId", "AtcNum");
return View(mdl);
}
[HttpGet]
public PartialViewResult GetRollView(decimal[] SelectedOurStyle)
{
LaySheetShortageViewModel model = new LaySheetShortageViewModel();
LaysheetRollRepository lyipores = new LaysheetRollRepository();
model.rolldetailcollection= lyipores.getlaysheetRollData(SelectedOurStyle);
return PartialView("LaySheetRollView",model);
}
[HttpPost]
public ActionResult ApproveLaysheet(LaySheetShortageViewModel Model)
{ // not gretting the value of rolldetailcollection here
return View();
}
My View
#model ArtWebApp.Areas.ArtMVC.Models.ViewModel.LaySheetShortageViewModel
<script type="text/javascript">
$(document).ready(function () {
$("#Show").click(function (e, params) {
debugger;
var SelectedOurStyle = new Array();
SelectedOurStyle = $("#LaySheetID").chosen().val();
if (SelectedOurStyle != null)
{
$.ajax({
url: "#Url.Action("GetRollView", "ApproveLaysheet")",
traditional: true,
data: { 'SelectedOurStyle': SelectedOurStyle },
type: "GET",
success: function (fooBarHTML) {
$("#output").html(fooBarHTML);
},
error: function (xhr, status, errorThrown) {
//...
}
});
}
});
});
</script>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SampCutReqMaster</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="row">
<div class="col-md-2">
#Html.Label("Atcc#", new { #class = "control-label col-md-2" });
</div>
<div class="col-md-10">
#Html.DropDownList("AtcID", null, htmlAttributes: new { #class = "chosen-select form-control" })
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-2">
#Html.Label("OurStyle#", new { #class = "control-label col-md-2" });
</div>
<div class="col-md-10">
#Html.DropDownList("OurStyleID", new MultiSelectList(string.Empty, "Value", "Text") , null, htmlAttributes: new { #class = "chosen-select form-control", #multiple = "multiple" } )
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-2">
#Html.Label("LaySheet#", new { #class = "control-label col-md-2" });
</div>
<div class="col-md-10">
#Html.DropDownList("LaySheetID", new MultiSelectList(string.Empty, "Value", "Text"), null, htmlAttributes: new { #class = "chosen-select form-control", #multiple = "multiple" })
</div>
</div>
</div>
<div id='output' class="">
<!-- Partialview Comes here -->
</div>
</div>
}
My Partial View
#using HtmlHelpers.BeginCollectionItem
#model ArtWebApp.Areas.ArtMVC.Models.ViewModel.LaySheetShortageViewModel
<script src="~/JQuery/GridJQuery.js"></script>
<script>
</script>
<div class="container">
<table class="table table-bordered table-striped table-responsive">
<tr>
<th>
#Html.CheckBox("SelectAll")
</th>
<th>
#Html.DisplayNameFor(model => model.approvelaysheetModel.LaySheetDet_PK)
</th>
<th>
#Html.DisplayNameFor(model => model.approvelaysheetModel.LayCutNum)
</th>
<th>
#Html.DisplayNameFor(model => model.approvelaysheetModel.RollNum)
</th>
</tr>
#if (Model != null)
{
for (int i = 0; i < Model.rolldetailcollection.Count; i++)
{
using (Html.BeginCollectionItem("rolldata"))
{
<tr>
<td>
#Html.EditorFor(modelItem => Model.rolldetailcollection[i].IsSelected, new { #onclick = "Check_ClickNew(this)" })
</td>
<td>
#Html.EditorFor(modelItem => Model.rolldetailcollection[i].LaySheetDet_PK)
#Html.HiddenFor(model => Model.rolldetailcollection[i].LaySheetDet_PK, new { htmlAttributes = new { #class = "form-control" } })
</td>
<td>
#Html.DisplayFor(modelItem => Model.rolldetailcollection[i].LayCutNum)
</td>
<td>
#Html.DisplayFor(modelItem => Model.rolldetailcollection[i].RollNum)
</td>
</tr>
}
}
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input id="Submit" type="submit" value="Submit Fabric request" class="btn btn-default show" />
</div>
</div>
</div>
My viewModals
public class ApprovelaysheetModel
{
public Decimal ApprovelaysheetModelID { get; set; }
[Display(Name ="ID")]
public Decimal LaySheetDet_PK { get; set; }
public Boolean IsSelected { get; set; }
public Decimal LaySheet_PK { get; set; }
}
public class LaySheetShortageViewModel
{
[Key]
[Display(Name = "ID")]
public Decimal ShortageID { get; set; }
public int Location_pk { get; set; }
public int Atcid { get; set; }
public int OurstyleID { get; set; } }
public List<ApprovelaysheetModel> rolldetailcollection { get; set; }
}
Can anyone suggest whats my mistake or any better method for doing this dataentry as Iam new to MVC
Your use of BeginCollectionItem() inside the for loop is prefixing your name attributes so that they no longer relate to your models properties. Instead of generating
<input type="checkbox" name="rolldetailcollection[0].IsSelected" ... />
your now generating
<input type="checkbox" name="rolldata[####].rolldetailcollection[0].IsSelected" ... />
where #### is a Guid.
Remove the BeginCollectionItem() code so that your loop is
for (int i = 0; i < Model.rolldetailcollection.Count; i++)
{
<tr>
<td>
#Html.EditorFor(m => m.rolldetailcollection[i].IsSelected, new { #onclick = "Check_ClickNew(this)" })
</td>
<td>
#Html.EditorFor(m => m.rolldetailcollection[i].LaySheetDet_PK)
// Note there is no point adding html attributes for a hidden input
#Html.HiddenFor(m => m.rolldetailcollection[i].LaySheetDet_PK)
</td>
....
</tr>
}
Note that the BeginCollectionItem() method is used when you want to dynamically add and remove items from a collection in the view in conjunction with javascript/ajax (refer this answer for an example). If you do want to do that, then you need to create a partial view (say) _ApprovelaysheetModel.cshtml for the model
#model ApprovelaysheetModel
// Note the name needs to match the collection property name
#using (Html.BeginCollectionItem("rolldetailcollection"))
{
....
#Html.EditorFor(m => m.LaySheetDet_PK)
....
}
and then in the main view you use a foreach loop
#foreach(var item in Model.rolldetailcollection)
{
#Html.Partial("_ApprovelaysheetModel", item)
}

MVC Razor POST - list object is always null

I've tried several times to get my complex object which contains a list to POST correctly. All the properties except the list object contain values when it posts. I've based my approach on this SO Q&A and this SO Q&A. However, in both case the solution is to use a for loop instead of a foreach loop. I'm using the recommended for loop but still have\ing an issue. I'm not sure what else could be causing the list to be null when posting. Thanks in advance for your help!
View:
#model PropertiesAdminSite.Models.UtilityData
#{
ViewBag.Title = "CreateNewCycle";
}
<h2>New Residence Utilities</h2>
#using (Html.BeginForm("Upload", "ImportWater", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="control-group">
#Html.TextBoxFor(m => m.UploadFile, new { type = "file"})
</div>
<div class="control-group">
<input type="submit" class="btn btn-info" value="Upload" />
</div>
<div class="col-lg-12 visible-lg">
<br>
<span style="color:green">#ViewBag.Message</span>
#Html.HiddenFor(model => model.bID)
#Html.HiddenFor(model => model.bEntryDate)
#Html.HiddenFor(model => model.bPrevDate)
#for (int i = 0; i < Model.utilData.Count(); i++)
{
#Html.HiddenFor(model => model.utilData[i].ResNumber)
#Html.HiddenFor(model => model.utilData[i].GrnLower)
#Html.HiddenFor(model => model.utilData[i].GrnUpper)
#Html.HiddenFor(model => model.utilData[i].prevWaterReading)
#Html.HiddenFor(model => model.utilData[i].rID)
#Html.HiddenFor(model => model.utilData[i].WaterReading)
#Html.HiddenFor(model => model.utilData[i].wDifference)
#Html.HiddenFor(model => model.utilData[i].YelLower)
#Html.HiddenFor(model => model.utilData[i].YelUpper)
}
</div>
}
#using (Html.BeginForm("IndexMulti", "Utilities", FormMethod.Post))
{
#Html.AntiForgeryToken()
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
#Html.LabelFor(model => model.bEntryDate, htmlAttributes: new { #class = "control-label col-md-1" })
#Html.DisplayFor(model => model.bEntryDate)
#Html.HiddenFor(model => model.bID)
#Html.HiddenFor(model => model.bEntryDate)
#Html.HiddenFor(model => model.bPrevDate)
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div class="dataTable_wrapper">
<!--div id="dataTables-example_wrapper" class="dataTables_wrapper form-inline dt-bootstrap no-footer">-->
<div class="row">
<div class="col-sm-12">
<table class="table table-striped table-bordered table-hover dataTable no-footer" id="dataTables-Bills" role="grid" aria-describedby="dataTables-example_info">
<!-- /table headers-->
<thead>
<tr role="row">
<th>#Html.DisplayNameFor(model => model.utilData.First().ResNumber)</th>
<th>#Html.DisplayNameFor(model => model.utilData.First().WaterReading)</th>
<th>
#Html.DisplayNameFor(model => model.utilData.First().prevWaterReading)
#Html.DisplayFor(model => model.bPrevDate)
</th>
<th>#Html.DisplayNameFor(model => model.utilData.First().wDifference)</th>
<th>Actions</th>
</tr>
</thead>
<!-- /table body-->
<tbody>
#for (int i = 0; i < Model.utilData.Count(); i++)
{
<tr role="row">
<td>
#Html.DisplayFor(modelItem => modelItem.utilData[i].ResNumber)
#Html.HiddenFor(model => model.utilData[i].GrnLower)
#Html.HiddenFor(model => model.utilData[i].GrnUpper)
#Html.HiddenFor(model => model.utilData[i].YelLower)
#Html.HiddenFor(model => model.utilData[i].YelUpper)
</td>
<td>
#Html.EditorFor(model => model.utilData[i].WaterReading)
</td>
<td>
<span id="#string.Format("prevWater_{0}",Model.utilData[i].rID)">
#Html.DisplayFor(model => model.utilData[i].prevWaterReading)
</span>
#Html.HiddenFor(model => model.utilData[i].prevWaterReading)
</td>
<td>
<span id="#string.Format("hdifference_{0}",Model.utilData[i].rID)">
#Html.DisplayFor(model => model.utilData[i].wDifference)
</span>
#Html.HiddenFor(model => model.utilData[i].prevWaterReading)
</td>
<td>
#Html.ActionLink("View History", "ExportDataIndex", "ExportData", new { rID = Model.utilData[i].rID, bId = Model.bID }, null) |
<a href="#Url.Action("ExportToExcel", "ExportData", new { rID = Model.utilData[i].rID, bId = Model.bID })" class="btn btn-success">
<i class="fa fa-file-excel-o" aria-hidden="true" title="Export to Excel"></i>
</a> |
<a href="#Url.Action("ChartData", "Utilities", new { rID = Model.utilData[i].rID, bId = Model.bID })" class="btn btn-info">
<i class="fa fa-bar-chart" aria-hidden="true" title="Water Usage History"></i>
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-0 col-md-8">
<input type="submit" value="Submit Water Readings and Create Invoices" class="btn btn-primary btn-lg btn-block" />
</div>
</div>
}
Model:
public partial class UtilityData
{
public DateTime bEntryDate { get; set; }
public string bPrevDate { get; set; }
public int bID { get; set; }
//public int residenceCount { get; set; }
public List<UtilEntry> utilData { get; set; }
public HttpPostedFileBase UploadFile { get; set; }
}
public partial class UtilEntry
{
public int rID { get; set; }
public long? WaterReading { get; set; }
public int ResNumber { get; set; }
public long? prevWaterReading { get; set; }
public decimal wDifference { get; set; }
public int GrnUpper { get; set; }
public int GrnLower { get; set; }
public int YelUpper { get; set; }
public int YelLower { get; set; }
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult IndexMulti([Bind(Include = "bEntryDate, bPrevDate,bID,uData")] UtilityData uData)
{
if (ModelState.IsValid)
{
Omitted for clarity
}
return RedirectToAction("Create", "TenantAccount", new { id = uData.bID});
}
Per #Stephen Muecke I had a typo in the IndexMulti Binding:
public ActionResult IndexMulti([Bind(Include = "bEntryDate, bPrevDate,bID,utilData")] UtilityData uData)
utilData was udata originally.

Unable to pass value to controller from view through viewmodel

I'm pretty sure my brain is friend and this is something I'm going to laugh at tomorrow morning, but unfortunately I'm stuck on this portion and am asking for assistance.
I have a ViewModel:
public class HousingDetailsViewModel : AppViewModel
{
DataContext db = new DataContext();
public List<string> units { get; set; }
public List<AvailableHousing> availableHousings { get; set; }
public Person person { get; set; }
public OccupiedHousing currentHousing { get; set; }
public OccupiedHousing newHousing;
public HousingDetailsViewModel(int? id)
{
units = db.AvailableHousings.OrderBy(ah => ah.Unit).Select(h => h.Unit).Distinct().ToList();
availableHousings = db.AvailableHousings.Where(h => h.Available == true).OrderBy(h => h.Bed)
.OrderBy(h => h.Room).ToList();
currentHousing = db.OccupiedHousing.Include(o => o.AvailableHousing)
.Include(o => o.Person).Where(o => o.PersonID == id && o.CurrentHousing == true).FirstOrDefault();
person = db.Persons.Find(id);
newHousing = new OccupiedHousing();
}
}
My controller methods for this view:
public ActionResult Details(int? id)
{
return View(new HousingDetailsViewModel(id));
}
[HttpPost]
public ActionResult Move(OccupiedHousing newHousing, int? personID)
{
newHousing.PersonID = personID;
newHousing.DateArrived = DateTime.Now;
newHousing.CurrentHousing = true;
newHousing.AvailableHousingID = housingID;
db.OccupiedHousings.Add(newHousing);
db.SaveChanges();
return RedirectToAction("Index", new HousingViewModel());
}
And my form works fine for all of my fields except for 1, and that's the AvailableHousingID. I've tried setting a hidden value. I put a breakpoint where I set the value of the hidden field and I watched it change, but it didn't make it to the controller. So I changed it to a form submission and tried to catch it as a routevalue and that didn't work either. I'm at a loss, can anyone see where I'm going wrong?
EDIT: Adding View
#model AppName.ViewModels.HousingDetailsViewModel
#{
ViewBag.Title = "Housing Details";
}
#Html.BeginForm("Move", "Housing", new { personID = #Model.person.ID }, FormMethod.Post, new { })
<script>
function setID(id) {
$('#HiddenHousingID').val(id);
$('#HiddenSubmit').click();
}
</script>
<h2>Housing Details</h2>
<div class="row">
<div class="col-xs-12 container">
<div class="col-xs-5">
<img src="//placehold.it/150x200/77CCDD/66BBCC" class="img-responsive" />
</div>
<div class="col-xs-7">
<h4>#Model.person.ComboName</h4>
<h4>#Model.currentHousing.AvailableHousing.Unit - #Model.currentHousing.AvailableHousing.Room - #Model.currentHousing.AvailableHousing.Bed</h4>
<h4>#Model.person.DateOfBirth.Value.ToShortDateString()</h4>
#Html.HiddenFor(m => m.newHousing.AvailableHousingID, new { id = "HiddenHousingID", name = "newHousing.AvailableHousingID")}
</div>
</div>
</div>
<div class="row">
#foreach (var unit in Model.units)
{
<div class="col-xs-6">
<div class="panel panel-primary">
<div class="panel-heading">
<span class="panel-title">
#unit
</span>
</div>
<div class="panel-body">
<table id="MoveHousingTable" class="table table table-condensed table-striped">
<thead>
<tr>
<th>
Available Housing
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var housing in Model.availableHousings.Where(h => h.Unit == unit))
{
<tr>
<td>
#housing.Room -
#housing.Bed
</td>
<td>
<input type="button" value="Select" name="select" onclick="setID(#housing.ID)" />
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
}
</div>
<input type="submit" class="hidden" id="HiddenSubmit">
}
For the route :
#Html.BeginForm("Move", "Housing", new { personID = #Model.person.ID , housingID= #Model.newHousing.AvailableHousingID}, FormMethod.Post, new { })

Multiple models in one view using IEnumerable

Problem Statement:
I want to create a view where first I'm accepting two parameters as a from date and to date and also a dropdown based on which one index in order to display all the details corresponding to the item selected in the combobox.
For this I've defined two models:
First model consists of the parameters which is to be inserted from the front end and again in the second model I'm defining all the parameters required to display in the index of that page.
Here is my model:
public class SearchModel
{
[Required]
[Display(Name = "From Date")]
public DateTime FromDate { get; set; }
[Required]
[Display(Name = "To Date")]
public DateTime ToDate { get; set; }
[Display(Name = "Search #")]
public String SearchNumber { get; set; }
}
public class IndexModel
{
[Required]
[Display(Name = "Search #")]
public string SearchNumber { get; set; }
[Key]
[Required]
[Display(Name = "SearchID")]
public int SearchID{ get; set; }
[Display(Name = "Received Date")]
public DateTime ReceivedDate { get; set; }
}
And finally I'm defining both of the models in a global Model as:
public class GlobalModel
{
public SearchModel SearchModel { get; set; }
public IndexModel IndexModel { get; set; }
}
Finally, when I try to write code in the view in index with GlobalModel as
#model IEnumerable<...SomePath.GlobalModel>
#{
ViewBag.Title = "Index";
}
<div style="padding-left: 40%">
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Search</legend>
<ol>
<li>
<div class="editor-label">
#Html.LabelFor(model => model.SearchModel.FromDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SearchModel.FromDate)
#Html.ValidationMessageFor(model => model.SearchModel.FromDate)
</div>
</li>
<li>
<div class="editor-label">
#Html.LabelFor(model => model.SearchModel.ToDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SearchModel.ToDate)
#Html.ValidationMessageFor(model => model.SearchModel.ToDate)
</div>
</li>
<li>
#Html.DropDownListFor(model => model.SearchModel.SearchNumber, new SelectList(Model.ddlSearchNo.ddlSearchNumber, "Value", "Text"), "Select Search #", new { id="SearchID",onchange="GetSearchNo()" })
#Html.ValidationMessageFor(model => model.FirstOrDefault().SearchModel.SearchNumber)
</li>
</ol>
</fieldset>
}
</div>
<div>
<table style="border-collapse: separate; border-spacing: 15px;">
<tr>
<th style="text-align:center;">
#Html.DisplayNameFor(model => model.IndexModel.SearchNumber)
</th>
<th style="text-align:center;">
#Html.DisplayNameFor(model => model.IndexModel.SearchID)
</th>
<th style="text-align:center;">
#Html.DisplayNameFor(model => model.IndexModel.ReceivedDate)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td style="text-align:center;">
#Html.DisplayFor(modelItem => item.IndexModel.SearchNumber)
</td>
<td style="text-align:center;">
#Html.DisplayFor(modelItem => item.IndexModel.SearchID)
</td>
<td style="text-align:center;">
#Html.DisplayFor(modelItem => item.IndexModel.ReceivedDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.IndexModel.SearchID}) |
#Html.ActionLink("Details", "Details", new{id=item.Model.SearchID}) |
#Html.ActionLink("Delete", "Delete", new {id=item.IndexModel.SearchID })
</td>
</tr>
}
</table>
</div>
Here,though I am using the global model name at the top and with the object of the global model I'm trying to access the parameters of the child models but I'm getting error like not
declared or cannot recognise.
I am able to access all the parameters of the child model if I use FirstorDefault() which was suggested by someone as :
#Html.LabelFor(model => model.FirstorDefault().SearchModel.FromDate)
but at the time of loading it throws exception as values cannot be null.
Again if I dont use Ienumerable in top then I'm getting error in the foreach loop.
Also I found in stackoverflow that I need to use Ienumerable while defining the child model in the parent model as :
public IEnumerable<SearchModel> SearchModel { get; set; }
public IEnumerable<IndexModel> IndexModel { get; set; }
but again some other error are there.
I just want to load my view which I'm not able even after lot of try and research.
What changes should I make...?
Any help would be appreciated.
In controller index action method,I've written code as:
public ActionResult Index()
{
var result = GetDetails();
return View(result);
}
and my method is:
public IEnumerable<GlobalModel> GetDetails()
{
return (from po in dbEntity.SearchDetails.AsEnumerable()
select new GlobalModel()
{
IndexModel = po
//SearchID = po.SearchID,
// //ReceivedDate = po.ReceivedDate,
}).ToList();
}
Here,I am passing the Global model for the view to be loaded that consists of two child models.Now since the Index details is coming from database ,so here also I'm not able to initialise all the parameters,since I am trying to initialise the entire model to the fields of the table which is not at all possible .
Also, I'm getting all the fields of the database table at po. but again not able to initialise as IndexModel refers to entire parameters of the Index Model.
So,I got stuck here.I need to solve this issue.Where am I doing wrong..?
As I can see you only want to loop through the IndexModel and SearchModel only have a single value. Try doing this approach:
Change your Global Model to:
public class GlobalModel
{
public SearchModel SearchModel { get; set; }
public IEnumerable<IndexModel> IndexModels { get; set; }
}
For your method to get the IndexModels:
public IEnumerable<IndexModel> GetDetails()
{
return (from po in dbEntity.SearchDetails
select new IndexModel()
{
SearchNumber = po.SearchNumber,
SearchID = po.SearchID,
ReceivedDate = po.ReceivedDate
}).ToList();
}
In your Action Method:
public ActionResult Index()
{
var model = new GlobalModel():
var model.IndexModels = GetDetails();
return View(model);
}
Finally in your View:
#model ProjectName.Model.GlobalModel
#{
ViewBag.Title = "Index";
}
<div style="padding-left: 40%">
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Search</legend>
<ol>
<li>
<div class="editor-label">
#Html.LabelFor(model => model.SearchModel.FromDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SearchModel.FromDate)
#Html.ValidationMessageFor(model => model.SearchModel.FromDate)
</div>
</li>
<li>
<div class="editor-label">
#Html.LabelFor(model => model.SearchModel.ToDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SearchModel.ToDate)
#Html.ValidationMessageFor(model => model.SearchModel.ToDate)
</div>
</li>
<li>
#Html.DropDownListFor(model => model.SearchModel.SearchNumber, new SelectList(Model.ddlSearchNo.ddlSearchNumber, "Value", "Text"), "Select Search #", new { id="SearchID",onchange="GetSearchNo()" })
#Html.ValidationMessageFor(model => model.SearchModel.SearchNumber)
</li>
</ol>
</fieldset>
}
</div>
<div>
<table style="border-collapse: separate; border-spacing: 15px;">
<tr>
<th style="text-align:center;">
#Html.DisplayNameFor(model => model.IndexModels.SearchNumber)
</th>
<th style="text-align:center;">
#Html.DisplayNameFor(model => model.IndexModels.SearchID)
</th>
<th style="text-align:center;">
#Html.DisplayNameFor(model => model.IndexModels.ReceivedDate)
</th>
</tr>
#foreach (var item in Model.IndexModels) {
<tr>
<td style="text-align:center;">
#Html.DisplayFor(modelItem => item.SearchNumber)
</td>
<td style="text-align:center;">
#Html.DisplayFor(modelItem => item.SearchID)
</td>
<td style="text-align:center;">
#Html.DisplayFor(modelItem => item.ReceivedDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.SearchID}) |
#Html.ActionLink("Details", "Details", new{id=item.SearchID}) |
#Html.ActionLink("Delete", "Delete", new {id=item.SearchID })
</td>
</tr>
}
</table>
</div>
let me know if it works.
The problem is because you don't initialize your Search model and the Index model!
First, you should modify your GetDetails method as follows
public IEnumerable<GlobalModel> GetDetails()
{
var models=(from po in dbEntity.SearchDetails.AsEnumerable()
select new GlobalModel()
{
IndexModel = new IndexModel(){
/* FromDate= po. FromDate,
ToDate= po. ToDate,*/
},
SearchModel = new SearchModel(){
/*SearchID = po.SearchID,
ReceivedDate = po.ReceivedDate,*/
},
}).ToList();
}
In addition, you'd better create an empty constructor for the IndexModel class and the SearchModel class as well. This constructor will initialize the class fields/properties.

Categories