C# MVC ViewModel One Posted Result Binds Whilst Others Are Null - c#

I have a number of awards in my view and within each award there is a corresponding list of qualifications. I have created a ViewModel to display each award and with a click of a button a modal should appear with its relevant qualifications which can be marked as completed/updated by the user. However on the Post of the data only my first Award will bind in my controller method.The rest will comeback as Null when I debug in VS. The data is appearing in my view as expected with each Award only showing its relevant qualifications. Thanks in advance for helping with this.
ViewModel
public class CandidateExtended
{
public CandidateExtended()
{
this.Qualifications = new List<Qualification_Extended>();
}
public int AwardID { get; set; }
public int FrameworkID { get; set; }
public string ULN { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string TitleShort { get; set; }
public string TitleFull { get; set; }
public DateTime DOB { get; set; }
public string Award { get; set; }
public int AwardLevel { get; set; }
public string Status { get; set; }
public string Completion { get; set; }
public string SelectedRoute { get; set; }
public List<Qualification_Extended> Qualifications { get; set; }
public void addQualification(Qualification_Extended qualification)
{
Qualifications.Add(qualification);
}
}
Controller
[HttpGet]
public ActionResult Index()
{
var awardDetails = (from award in db.award
join candidate in db.candidate
on award.ULN equals candidate.ULN
join framework in db.framework
on award.QAN equals framework.QAN
where award.OrganisationIdentityID == organisationID
select new AwardDetails_Extended
{
AwardID = award.AwardID,
ULN = award.ULN,
AwardStatus = award.AwardStatus,
Forename = candidate.Forename,
Surname = candidate.Surname,
DOB = candidate.DOB,
FrameworkID = framework.FrameworkID,
TitleFull = framework.TitleFull,
TitleShort = framework.TitleShort,
AwardLevel = framework.AwardLevel,
Award = framework.Award,
Completion = framework.Completion
}).ToList();
var qualificationDetails = (from candidateQualification in db.candidateQualification
join qualification in db.qualification
on candidateQualification.QualificationID equals qualification.QualificationID
select new Qualification_Extended
{
ID = candidateQualification.ID,
QualificationID = candidateQualification.QualificationID,
ULN = candidateQualification.ULN,
FrameworkID = candidateQualification.FrameworkID,
Achieved = candidateQualification.Achieved,
DateAchieved = candidateQualification.DateAchieved
}).ToList();
List<CandidateExtended> candidateVM = new List<CandidateExtended>();
foreach (var item in awardDetails)
{
CandidateExtended vm = new CandidateExtended();
vm.AwardID = item.AwardID;
vm.FrameworkID = item.FrameworkID;
vm.ULN = item.ULN;
vm.Forename = item.Forename;
vm.Surname = item.Surname;
vm.DOB = item.DOB;
vm.TitleShort = item.TitleShort;
vm.TitleFull = item.TitleFull;
vm.Award = item.Award;
vm.AwardLevel = item.AwardLevel;
vm.Status = item.AwardStatus;
vm.Completion = item.Completion;
vm.SelectedRoute = item.SelectedRoute;
foreach (var qualification in qualificationDetails)
{
if (qualification.ULN == item.ULN && qualification.FrameworkID == item.FrameworkID)
{
vm.addQualification(qualification);
}
}
candidateVM.Add(vm);
}
return View(candidateVM);
}
View
#model List<Apprenticeship_SingleAward.ViewModels.CandidateExtended>
#{
ViewBag.Title = "Single Award Apprenticeships";
Layout = "~/Views/Shared/_Organisation.cshtml";
}
<div class="application-table table-responsive">
<table class="table table-striped administration-table">
<thead>
<tr class="admin-table-heading">
<th>ULN</th>
<th>First Name</th>
<th>Last Name</th>
<th>Title</th>
<th>Award</th>
<th>Level</th>
<th>Qualifications</th>
<th>Status</th>
</tr>
</thead>
<tbody>
#for (int j = 0; j < Model.Count(); j++)
{
var award = Model[j];
<tr>
<td>#award.ULN</td>
<td>#award.Forename</td>
<td>#award.Surname</td>
<td>#award.TitleShort</td>
<td>#award.Award</td>
<td>#award.AwardLevel</td>
<td>
<button class="btn qualificationbutton" data-toggle="modal" data-target="##qualificationModal">#displayQualTotal<i class="glyphicon glyphicon-pencil org-edit-icon"></i></button>
#using (Html.BeginForm("UpdateAward", "Organisation", FormMethod.Post, new { id = award.AwardID}))
{
#Html.HiddenFor(a => Model[j].AwardID)
<div id="#qualificationModal" class="modal fade" role="dialog">
<div class="modal-dialog organisationmodal">
<div class="modal-content">
<div class="modal-body">
<h4 class="org-modal-subheading">#award.TitleShort</h4>
<br />
<div class="row">
<div class="col-md-12">
<div class="row org-row-main">
<div class="col-md-7"><h4 class="org-type">Qualification</h4></div>
<div class="col-md-2"><h5 class="org-completed">Completed</h5></div>
<div class="col-md-3"><h5 class="org-date">Date</h5></div>
</div>
<hr class="org-hr"/>
#for (int i = 0; i < Model[j].Qualifications.Count(); i++)
{
<div class="row org-row">
<div class="col-md-7">
#Html.HiddenFor(a => Model[j].Qualifications[i].ID)
</div>
<div class="col-md-2">
#Html.CheckBoxFor(a => Model[j].Qualifications[i].Achieved)
</div>
<div class="col-md-3"
>#Html.TextBoxFor(a => Model[j].Qualifications[i].DateAchieved, "{0:dd/MM/yyyy}")
</div>
</div>
}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn ccea-signout" data-dismiss="modal">Close</button>
<button type="submit" class="btn admin-button" style="margin-top: 0;">Save</button>
</div>
</div>
</div>
</div>
}
</td>
<td>
#{
var status = award.Status;
if (status == "In Progress")
{
<button class="btn progressbutton" style="margin: 0;">#status</button>
}
}
</td>
</tr>
}
</tbody>
</table>
UpdateAward
[HttpPost]
public ActionResult UpdateAward(List<CandidateExtended> Model)
{
return RedirectToAction("Index", "Login");
}

The way it is set up now (with BeginForm inside the #for, and a Submit button for every 'mini'-Form), every submit will do a Form Post containing exactly one item from the list.
If that is how you want it to work (edit one item at a time), then you may keep it. Do keep in mind however (add a comment?) that even though the Post Action method is ready to receive a List, there never will be multiple items in the List because each 'mini'-Form contains just one item.
If on the other hand you want to be able to save multiple items at once, then move the BeginForm outside the #for, and use just one Submit button at the end of the Form, e.g. just before the closing }.

Related

List of objects is empty in my model when posting

When I'm posting my form my list of objects is always empty and I can't figure out why. I searched and read through the dozen similar questions and still no go. The fields in my model are posted back with the exception of the TimeAdds list. Any help is appreciated.
My controller
public ActionResult TimeAdd()
{
TimeAddModel model = new TimeAddModel();
model.StartDate = DateTime.Now;
model.EndDate = DateTime.Now;
model.TypeId = 1;
model.TimeAdds = new List<TimeAdd>();
return View(model);
}
[HttpPost]
public ActionResult TimeAdd(TimeAddModel model)
{
if (Request.Form["dateRange"] != null) {
ModelState.Clear();
TimeAdd t = new TimeAdd();
t.Id = Guid.NewGuid();
t.TypeId = model.TypeId;
model.TimeAdds.Add(t);
}
else {
//save
}
return View(model);
}
My Class
public class TimeAdd
{
[Key]
public Guid Id { get; set; }
public int TypeId { get; set; }
}
My Model
public class TimeAddModel
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int TypeId { get; set; }
public List<TimeAdd> TimeAdds { get; set; }
public TimeAddModel()
{
this.TimeAdds = new List<TimeAdd>();
}
}
and my page
#model metrosales.Models.TimeAddModel
#using metrosales.Data.TimeOff.Model
<div class="container excess">
#using (Html.BeginForm("TimeAdd", "Service", FormMethod.Post)) {
<div class="row">
<div class="col-sm-6">
#Html.LabelFor(model => model.StartDate)
#Html.TextBoxFor(x => x.StartDate, "{0:yyyy-MM-dd}", new { #class = "form-control", #type = "date", #id = "StartDate", #name = "StartDate" })
</div>
<div class="col-sm-6">
#Html.LabelFor(model => model.EndDate)
#Html.TextBoxFor(x => x.EndDate, "{0:yyyy-MM-dd}", new { #class = "form-control", #type = "date", #id = "EndDate", #name = "EndDate" })
</div>
</div>
<input type="submit" class="btn text-center" name="dateRange" value="Submit1" />
<input type="submit" class="btn text-center" name="submit" value="Submit2" />
}
<div>
<br />
<table id="tblExcess" class="table" cellpadding="0" cellspacing="0">
<tr>
<th>ID</th>
<th>Start</th>
</tr>
#for (var i = 0; i < Model.TimeAdds.Count(); i++) {
<tr>
<td>#Html.HiddenFor(model => model.TimeAdds[i].Id)</td>
<td>#Html.TextBoxFor(model => model.TimeAdds[i].TypeId)</td>
</tr>
}
</table>
</div>
To be able the MVC perform the data binding correctly it is necessary to prepare the context in the TimeAdd view.
Therefore, to provide an index for each item in the TimeAdds list make following changes in the TimeAdd.cshtml:
#Html.Hidden("TypeId", Model.TypeId)
#for (var i = 0; i < Model.TimeAdds.Count(); i++)
{
#Html.Hidden("TimeAdds[" + i + "].Id", Model.TimeAdds[i].Id)
#Html.Hidden("TimeAdds[" + i + "].TypeId", Model.TimeAdds[i].TypeId)
<tr>
<td>#Html.TextBoxFor(model => Model.TimeAdds[i].Id)</td>
<td>#Html.TextBoxFor(model => Model.TimeAdds[i].TypeId)</td>
</tr>
}

The model item passed into the ViewDataDictionary is of type Error

My app may be bad I'm trying to learn
What is the solution for this error?
The error i got
Controller
I do not know exactly how to make the list, the examples I tried did not work
I guess I need to make a list somehow
public IActionResult Rooms()
{
using (var db = new HotelWebContext())
{
var roomList = db.Rooms.Where(z => z.OtherTypeId == z.OtherType.OtherTypeId && z.RoomTypeId == z.RoomType.RoomTypeId && z.StatusId == z.Status.RoomStatusId).Select(r => new { r.RoomId, r.OtherType.OtherTypeName, r.OtherType.BasePrice, r.OtherType.Capacity, r.OtherType.BedType, r.OtherType.Services, r.RoomType.RoomTypeName, r.Status.RoomStatusName }).ToList();
return View(roomList);
}
}
Model
I created it automatically with the entity framework
public partial class Room
{
public Room()
{
Reservations = new HashSet<Reservation>();
}
public int RoomId { get; set; }
public int? RoomTypeId { get; set; }
public int? OtherTypeId { get; set; }
public int? StatusId { get; set; }
public virtual OtherType OtherType { get; set; }
public virtual RoomType RoomType { get; set; }
public virtual RoomStatus Status { get; set; }
public virtual ICollection<Reservation> Reservations { get; set; }
}
Rooms.cshtml have a foreach loop
#model IEnumerable<WebApplication3.Models.Room>
#{
ViewData["Title"] = "Odalarımız";
ViewData["Dark"] = "text-dark";
ViewData["Info"] = "text-info";
}
<div class="odafiyatlari mx-auto">
<div class="odaimg">
<div class="container">
<h1 style="margin-top: 200px; margin-bottom: 200px;font-family: 'Playfair Display', serif;" class="text-center text-dark ">ODALARIMIZ</h1>
<div class="row">
<!-- #for (int i = 0; i < 0; i++)
{
<div class="col-xl-4 py-4">
<div style="border-radius: 10px;" class="card mx-auto" style="width: 18rem;">
<img class="card-img-top " src="~/images/oda1.jpg" alt="Card image cap">
<div class="card-body">
<h6 class="card-text">Durum:Uygun</h6><br>
<h5 class="card-title">İki Kişilik İkiz Yataklı Oda</h5>
<h5 class="card-title">Oda Tipi:Aile</h5>
<h6 class="card-text">399₺ / Gecelik</h6><br>
<h6 class="card-text">Kapasite: İki Kişilik</h6><br>
<h6 class="card-text">Yatak: Kral Yatak</h6><br>
<h6 class="card-text">Servis: İnternet, Televizyon, Duş</h6><br>
Odayı Seç
</div>
</div>
</div>
}-->
#foreach (var item in Model)
{
<div class="col-xl-4 py-4">
<div style="border-radius: 10px;" class="card mx-auto" style="width: 18rem;">
<img class="card-img-top " src="~/images/oda1.jpg" alt="Card image cap">
<div class="card-body">
<h6 class="card-text">Durum:#item.Status.RoomStatusName</h6><br>
<h5 class="card-title">#item.OtherType.OtherTypeName</h5>
<h5 class="card-title">Oda Tipi:#item.RoomType.RoomTypeName</h5>
<h6 class="card-text">#item.OtherType.BasePrice₺ / Gecelik</h6><br>
<h6 class="card-text">Kapasite: #item.OtherType.Capacity</h6><br>
<h6 class="card-text">Yatak: #item.OtherType.BedType</h6><br>
<h6 class="card-text">Servis: #item.OtherType.Services</h6><br>
Odayı Seç
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<!--ODA BİTİŞ-->
Model
Your are projecting your Rooms into a new anonymous object with values by calling
.Select(r => new { r.RoomId, r.OtherType.OtherTypeName, r.OtherType.BasePrice, r.OtherType.Capacity, r.OtherType.BedType, r.OtherType.Services, r.RoomType.RoomTypeName, r.Status.RoomStatusName })
So now you got an IEnumerable of anonymous type.
But the action expects to return an IEnumerable of Rooms.
Just remove the select you should be good, since you are retrieving from rooms table.
You need use .Include() method to include the related models like below:
var model = db.Rooms
.Where(z => z.OtherTypeId == z.OtherType.OtherTypeId && z.RoomTypeId == z.RoomType.RoomTypeId && z.StatusId == z.Status.RoomStatusId)
.Include(r=>r.OtherType)
.Include(r=>r.RoomType)
.Include(r=>r.Status)
.ToList();
The List you are passing to view that should be type of Room Class.

return to partial view as json?

i had 2 views the "index" and "_Track". i need to return my datalist to "_Track"-this is partial view. can someone help me becoz i got this error. i need to return the data list into partial view.
Error
"for each statement cannot operate on variable type does not contain a public instance definition for getenumerator"
see the reference code below.
Parent model.
public class TrackingFormModel : BaseModel
{
public string TrackingNumber { get; set; }
public TrackingListModel TrackingList { get; set; }
}
Child model
public class TrackingListModel : BaseModel
{
public string Name { get; set; }
public string Departure { get; set; }
}
Index.cshtml
#using ChenvelMobile.Web.Models.Tracking
#model TrackingFormModel
#{
ViewBag.Title = "index";
Layout = null;
}
#using (Html.BeginForm("index", "tracking", FormMethod.Post))
{
#Html.HiddenFor(x => x.Id)
<div class="MainContainer">
<div class="row">
<div class="form-group">
<div class="col-md-12">
<h4>Track an Item</h4>
<p>Hint: Enter the correct tracking number (Example. AU0002004)</p>
<div class="input-group">
#Html.TextBoxFor(x => x.TrackingNumber, new { #class = "form-control", #id = "testSize", #placeholder = "Enter your box number..." })
<div class="input-group-btn">
<button class="btn btn-primary" type="submit" id="show">
<span class="glyphicon glyphicon-search btnSize" style="font-size: 20px"></span>
</button>
</div>
</div>
<br />
#Html.Partial("_Track", Model)
</div>
</div>
</div>
</div>
}
_Track.cshtml(Partial View)
#using ChenvelMobile.Web.Models.Tracking
#model TrackingListModel
#foreach (var item in Model)
{
<div>#item.Id</div>
<div>#item.Name</div>
<div>#item.Departure</div>
}
Controller
public JsonResult Index(TrackingFormModel model)
{
string date = String.Format("{0:MM/dd/yyyy}", DateTime.Now);
DateTime startdate = DateTime.Parse(date);
DateTime prevoiusdate = startdate.AddDays(-90);
var tracking = _cSI_DataService.Find(x => x.reciept_id == model.TrackingNumber).Where(x => Convert.ToDateTime(x.date_pl) > prevoiusdate).ToList();
var list = (from t in tracking
join d in _departureItemsTableService.GetAll() on t.box_id.Trim() equals d.BoxNo.Trim() into departitem from departitems in departitem.DefaultIfEmpty()
join dt in _departureTableService.GetAll() on departitems?.DepartureId equals dt.DepartureId into dep from depart in dep.DefaultIfEmpty()
select new TrackingListModel
{
Id = t.Id,
Name = t.firstname_s + " " + t.lastname_s,
Departure = depart?.DepartureDate ?? String.Empty,
});
return Json(new { data = list.ToList() }, JsonRequestBehavior.AllowGet);
}
Try passing the tracking list to your partial view. Currently you are passing a TrackingFormModel, not the expected TrackingListModel.
#Html.Partial("_Track", Model.TrackingList)

how i can add second model to this view? [duplicate]

This question already has answers here:
Multiple models in a view
(12 answers)
Closed 5 years ago.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
add my code
i want add second model to my view and i dont know how i can do it. i use pagedList i first model.
view:
#model PagedList.IPagedList<ForumIT.ViewModels.Lista>
#using ForumIT;
#using PagedList.Mvc;
#{
ViewBag.Title = "Materiały";
}
<div class="jumbotron">
<h1>Forum Dyskusyjne IT</h1><br />
<p class="lead">Forum poświęcone jest szeroko rozwiniętej dziedzinie informatyki. Przedstaw swój problem w temacie i przedyskutuj go z dużym gronem użytkowników służących pomocą</p>
</div><br /><br />
<div class="row">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading"><h3>Tematy</h3></div>
</div>
<div class=" panel panel-default" style="padding: 10px">
<hr />
#foreach (var item in Model)
{
<div class="media">
<div class="media-left" style="padding-right: 30px">
<img class="media-object img-circle"
src="~/Graphics/Users/#((item.Foto!=null)?#item.Foto:"user.png")"
alt="zdjęcie"
width="64">
<h6><b>#item.Autor</b></h6>
</div>
<div class="media-body">
<h4 class="media-heading">
<a title="Czytaj" href="#Url.Action("Details", "Temat", new { id = item.IdTematu })">
<h1 style="margin-top: 0px">#item.Tytul</h1>
</a>
</h4>
<p style="max-width: 600px; max-height: 95px">#item.Tresc</p>
</div>
</div>
<hr />
}
</div>
<div class="row">
Strona #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) z #Model.PageCount
<div class="pull-right">
#Html.PagedListPager(Model, Page => Url.Action("Index", new { strona = Page }))
</div>
</div>
</div>
<div class="col-md-4">
<div class="list-group">
<div class="panel panel-default">
<div class="panel-heading"><h3>Kategorie</h3></div>
</div>
<a href="~/Home/index">
<button type="button" class="list-group-item">Wszystkie Kategorie</button>
</a>
#foreach (var item in Model)
{
<a href="~/Home/index/2">
<button type="button" class="list-group- item">#item.NazwaKategorii</button>
</a>
}
</div>
</div>
</div>
Controller:
using ForumIT.Models;
using ForumIT.ViewModels;
using PagedList;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ForumIT.Controllers
{
public class HomeController : Controller
{
private ForumContext db = new ForumContext();
public ActionResult Index(int? id = 0, int? rozmiar = 5, int? strona = 1)
{
IQueryable<Lista> lista = from t in db.Tematy
orderby t.DataDodania descending
select new Lista()
{
IdTematu = t.IdTematu,
Tytul = t.Tytul,
Tresc = t.Tresc,
Autor = t.Uzytkownik.Imie + " " + t.Uzytkownik.Nazwisko,
Foto = t.Uzytkownik.Foto,
IdKategorii = t.IdKategorii
};
IQueryable<Lista> lista2 = from k in db.Kategorie
select new Lista()
{
NazwaKategorii = k.NazwaKategorii,
Ikona = k.Ikona,
IdKategoriiK = k.IdKategorii
};
if (id != 0)
{
lista = lista.Where(l => l.IdKategorii == id);
}
return View(lista.ToPagedList((int)strona, (int)rozmiar));
}
i add class lista
namespace ForumIT.ViewModels
{
public class Lista
{
public int IdTematu { get; set; }
public string Tytul { get; set; }
public string Tresc { get; set; }
public string Autor { get; set; }
public string Foto { get; set; }
public int IdKategorii { get; set; }
public string NazwaKategorii { get; set; }
public string Ikona { get; set; }
public int IdKategoriiK { get; set; }
}
}
Add an additional view model like
public class MyViewModel
{
public PagedList.IPagedList<ForumIT.ViewModels.Lista> PagedList { get; set; }
public Models.SecondModel SecondModel { get; set; }
}
and then you can pass MyViewModel containing both the PagedList and the SecondModel to the view like
return View(new MyViewModel {PagedList = lista.ToPagedList((int)strona, (int)rozmiar),
SecondModel = new SecondModel()};
and in the view you would write something like
#model MyViewModel
#Model.PagedList.Count
#Model.SecondModel.YourProperty
You should merge the lists into a model class;
var indexModel = new IndexModel()
{
ListA = lista,
ListB = listb
};
return View(indexModel);
Index model;
public class IndexModel
{
public PagedList.IPagedList<ForumIT.ViewModels.Lista> ListA { get; set; }
public PagedList.IPagedList<ForumIT.ViewModels.Lista> ListB { get; set; }
}
Then change view model;
#model IndexModel

Display list of objects and set a value field for each input MVC

I have the following class defined as my ViewModel
public class CreateApplicationViewModel
{
public Step1ViewModel Step1 { get; set; }
public Step2StandAloneViewModel Step2StandAlone { get; set; }
public Step2ChildViewModel Step2Child { get; set; }
public Step3ViewModel Step3 { get; set; }
public Step4ViewModel Step4 { get; set; }
}
I'm trying to display items in the Step4ViewModel which consists of the following:
public class Step4ViewModel
{
public List<DataDetails> DataDetails = new List<DataDetails>();
}
public class DataDetails
{
public string GroupCode { get; set; }
public string GroupDesc { get; set; }
public decimal DetailSequence { get; set; }
public string DetailCode { get; set; }
public string DetailDesc { get; set; }
public string YesNoFlag { get; set; }
public string NumberFlag { get; set; }
public string ValueFlag { get; set; }
public string DateFlag { get; set; }
public string ListValuesFlag { get; set; }
public string CommentFlag { get; set; }
public string CalcRateFlag { get; set; }
public string ColumnSequence { get; set; }
public string TextFlag { get; set; }
public string CheckboxFlag { get; set; }
public string YesNoValue { get; set; }
public int NumberValue { get; set; }
public DateTime DateValue { get; set; }
public string ListValue { get; set; }
public string CommentValue { get; set; }
public string TextValue { get; set; }
public bool CheckboxValue { get; set; }
}
In my controller I populate the Step4ViewModel.DataDetails like so:
private Step4ViewModel GetCaseDataDetails(string caseType)
{
Step4ViewModel model = new Step4ViewModel();
List<DataDetails> data = new List<DataDetails>();
List<DataDetailsValues> values = new List<DataDetailsValues>();
var dataDetails = (from tb1 in db.DEFAULT_CASE_DATA_VW
join tb2 in db.CASE_DATA_DETAIL on tb1.CASE_DATA_GROUP_ID equals tb2.CASE_DATA_GROUP_ID
where tb1.BUS_CASE_CODE == caseType
orderby tb2.DETAIL_SEQUENCE
select new { tb1, tb2 });
foreach (var detail in dataDetails.ToList())
{
DataDetails i = new DataDetails();
DataDetailsValues j = new DataDetailsValues();
i.CalcRateFlag = detail.tb2.CALC_RATE_FLAG;
i.CheckboxFlag = detail.tb2.CHECKBOX_FLAG;
i.ColumnSequence = detail.tb2.COLUMN_SEQUENCE;
i.CommentFlag = detail.tb2.COMMENT_FLAG;
i.DateFlag = detail.tb2.DATE_FLAG;
i.DetailCode = detail.tb2.DETAIL_CODE;
i.DetailDesc = detail.tb2.DETAIL_DESC;
i.DetailSequence = detail.tb2.DETAIL_SEQUENCE;
i.GroupCode = detail.tb1.GROUP_CODE;
i.GroupDesc = detail.tb1.GROUP_DESC;
i.ListValuesFlag = detail.tb2.LIST_VALUES_FLAG;
i.NumberFlag = detail.tb2.NUMBER_FLAG;
i.TextFlag = detail.tb2.TEXT_FLAG;
i.ValueFlag = detail.tb2.VALUE_FLAG;
i.YesNoFlag = detail.tb2.YES_NO_FLAG;
data.Add(i);
}
model.DataDetails = data;
return model;
}
My thought process with the Step4ViewModel is that for every DataDetail I will display the DetailDesc as a label and then beside of it I will have an input for the NumberValue, YesOrNoValue, NumberValue, DateValue, ListValue, CommentValue, TextValue, or CheckboxValue depending on the control type and then post that data to server. I am able to successfully display each DataDetail.DetailDesc, but for each input, which also renders, the values I enter into the inputs never post back to the server. Here is what my view looks like:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => Model.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => Model.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
Controller to which post data
[HttpPost]
public ActionResult Step4(Step4ViewModel step4)
{
if (ModelState.IsValid)
{
CreateApplicationViewModel model = (CreateApplicationViewModel)Session["case"];
// model.Step4 = step4;
Session["case"] = model;
return View();
}
return View();
}
I was thinking this could be due the grouping, which I do to separate each group into a separate HTML panel element, but my inputs are rendering with the index number in the name. Any help or suggestions on a better way to accomplish this would be greatly appreciated. Cheers!
UPDATE
Here is my updated post controller and view:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
<input type="hidden" name="Step4.DataDetails.Index" value="#index" />
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => val.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => val.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
index++;
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
[HttpPost]
public ActionResult Step4(CreateApplicationViewModel step4)
{
if (ModelState.IsValid)
{
CreateApplicationViewModel model = (CreateApplicationViewModel)Session["case"];
// model.Step4 = step4;
Session["case"] = model;
return View();
}
return View();
}
UPDATE 2
I am able to get the form input if I pass a FormCollection to the HttpPost controller. Any ideas as to why I can get these values as a FormCollection but not as the model?
You are posting list of complex objects. But MVC DefaultModelBinder can’t able to bind to your DataDetails object because Index must be in sequence when posting the form with list of complex objects. In your case due to nested for loop, this sequence is broken. So what you can do is take one separate variable and initialize with default 0 value like this - I have tried to modify your code.
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
<input type="hidden" name="Step4.DataDetails.Index" value="#index" />
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => val.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => val.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
index++;
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
Look at the hidden field i have added in the view. That do the trick to post your data even with the broken sequences. Hope this help you.
I was able to get the model back to the controller by taking the idea of using an index integer and incrementing it from the answer above and implementing the idea in a different way in my view:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#Html.TextBoxFor(val => val.Step4.DataDetails[index].TextValue)
#Html.HiddenFor(val => val.Step4.DataDetails[index].GroupCode)
</div>
</div>
</div>
index++;
}
</div>
</div>
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
The above code in the view gives me the proper index of every element and allows me to post

Categories