I have a list of products that each one needs the amounts to return and the reason for return. I cannot change the model referenced (as it determines many of the values) How do I get the list of all the inputs to pass to the controller?
I tried to use javascript to send the information through but I have no real idea what I'm doing connecting razor to javascript.
My View:
..#model Snow_System.Models.mvcProductOrderModel
#{
ViewBag.Title = "Take in Order Return";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1 class="page-header pageHeading" style="text-align:center;">Take in Returned Stock</h1>
<hr />
<div class="TopInfoContainer">
<h2 class="SectionHeading">Order Information</h2>
<div class="TopInfoLeft">
<label for="ordID"> Order ID: </label> <span name="ordIDInfo"> #Model.ProductOrderID</span><br />
<label for="ordDate"> Date placed:</label> <span name="ordDate">#Model.DateOfOrder</span>
</div>
<div class="TopInfoRight">
<label for="ordLocation">Order Location:</label> <span name="ordLocation"> #Model.Client.HouseAddress</span><br />
</div>
</div>
<br />
<h2 class="SectionHeading">Product list</h2>
<table class="table">
<tr class="table-primary">
<th>
Name
</th>
<th>
Type
</th>
<th>
Quantity on Hand
</th>
<th>
Amount Ordered
</th>
<th>
Amount to Return
</th>
<th>
Reason for Return
</th>
<th>
Payback Amount
</th>
</tr>
#foreach (var item in Model.ProductOrderLines)
{
<tr class="table-dark" style="cursor:default;">
<td>
#Html.DisplayFor(modelItem => item.Product.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Product.ProductType)
</td>
<td>
#Html.DisplayFor(modelItem => item.Product.QuantityOnHand)
</td>
<td>
#Html.DisplayFor(modelItem => item.QuantityOrdered)
</td>
<td>
<input type="number" class="form-control return-amount" max="#item.QuantityOrdered" min="0" value="0" onchange="CalcSubtotal(#item.ProductID, this, #item.Product.SellingPrice)" />
</td>
<td>
<input type="text" placeholder="Reason for return" class="form-control return-reason" />
</td>
<td id="#item.ProductID">
</td>
</tr>
}
</table>
<div id="AuxilaryOptionsContainer">
</div>
<br />
<br />
<div onclick="document.getElementById('ReturnOrderModal').style.display='block'" class="OptionButton ContinueBtn btn btn-success" style="float:right"><span class="glyphicon glyphicon-ok-circle"></span> <br />Capture Return</div>
<div class="OptionButton BackBtn btn btn-danger" style="position: relative; bottom: 0; left: 0; "><span class="glyphicon glyphicon-remove-circle"></span><br />Cancel</div>
<script>
$(document).ready(function () {
$("#emailSuppliers .btn").click(function () {
$(this).button('toggle');
});
});
function CalcSubtotal(id, input, price) {
document.getElementById(id).innerHTML = "R" + input.value * price + ".00";
}
</script>
<div id="ReturnOrderModal" class="modal animate-opacity">
<div class="modal-content modal-background">
<header class="">
<h2>Confirm Return</h2>
</header>
<hr style="margin:0;" />
<div style="text-align:center; font-size:500%"><span class="glyphicon glyphicon-info-sign" style="margin-top:3%;"></span></div>
<div class="">
<p>Are you sure you want to return this order?</p>
</div>
<hr style="margin:0;" />
<footer class="" style="">
<div onclick="document.getElementById('ReturnOrderModal').style.display='none'" class="btn btn-outline-danger" style="width:25%; margin:2%; margin-top:2%;"><span class="glyphicon glyphicon-remove-circle"></span><br />No</div>
<div class="btn btn-outline-success" style="width:25%; margin:2%; margin-top:2%;"><span class="glyphicon glyphicon-ok-circle"></span><br />Yes</div>
</footer>
</div>
</div>
My Models
Product order line:
namespace Snow_System.Models
{
using System;
using System.Collections.Generic;
public partial class mvcProductOrderLineModel
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public mvcProductOrderLineModel()
{
this.ProductOrderReturnLines = new HashSet<mvcProductOrderReturnLineModel>();
}
public double Selling_Price { get; set; }
public int QuantityOrdered { get; set; }
public int QuantityDelivered { get; set; }
public System.DateTime OrderDate { get; set; }
public int ProductID { get; set; }
public int ProductOrderID { get; set; }
public virtual mvcProductModel Product { get; set; }
public virtual mvcProductOrderModel ProductOrder { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<mvcProductOrderReturnLineModel> ProductOrderReturnLines { get; set; }
}
}
Product order
namespace Snow_System.Models
{
using System;
using System.Collections.Generic;
public partial class mvcProductOrderModel
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public mvcProductOrderModel()
{
this.ProductOrderLines = new HashSet<mvcProductOrderLineModel>();
}
public int ProductOrderID { get; set; }
public System.DateTime DateOfOrder { get; set; }
public int ProductOrderStatusID { get; set; }
public int Client_ID { get; set; }
public virtual mvcClientModel Client { get; set; }
public virtual mvcProductOrderStatuModel ProductOrderStatu { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<mvcProductOrderLineModel> ProductOrderLines { get; set; }
}
}
Product order returns
namespace Snow_System.Models
{
using System;
using System.Collections.Generic;
public partial class mvcProductOrderReturnLineModel
{
public int ProductOrderID { get; set; }
public int ProductOrderReturnID { get; set; }
public int Quantity { get; set; }
public string ReasonForReturn { get; set; }
public int ProductID { get; set; }
public virtual mvcProductOrderLineModel ProductOrderLine { get; set; }
public virtual mvcProductOrderReturnModel ProductOrderReturn { get; set; }
}
}
I need inputs and the productID (Model.Product.ID) in the table to be passed to the controller.
Start by doing a for loop
#for (int i =0;i<Model.ProductOrderLines.Count;i++)
Then use the index to display and textbox
#Html.DisplayFor(modelItem => Model.ProductOrderLines[i].Product.Name)
#Html.TextboxFor(modelItem => Model.ProductOrderLines[i].QuantityOrdered)
When you receive the data back to the controller, it'll know under which index all the data are for (see for yourself by doing a view source). You can also receive a FormCollection collection and call TryUpdateModel to update the model.
You can use #Html.HiddenFor as solution of your purpose. Here is the steps to resolved your problem. You may take a look as your solution.
Model Class (Product Model And ProductItem)
public class ProductItem
{
public string Name { get; set; }
public string Type { get; set; }
public int QuantityOnHand { get; set; }
public int AmountOrdered { get; set; }
public int AmountToReturn { get; set; }
public string ReasonForReturn { get; set; }
public int PaybackAmount { get; set; }
}
public class ProductModel
{
public ProductModel()
{
ProductItems = new List<ProductItem>();
}
public List<ProductItem> ProductItems { get; set; }
}
Controller (ProductController)
public class ProductController : Controller
{
[HttpGet]
public IActionResult Product()
{
ProductModel productModel = GetProductModels();
return View(productModel);
}
[HttpPost]
public IActionResult Product(ProductModel productModel)
{
int productCount = productModel.ProductItems.Count;
return View(productModel);
}
private ProductModel GetProductModels()
{
ProductModel productModel = new ProductModel();
productModel.ProductItems.Add(new ProductItem() { Name = "Product_1", Type = "A", QuantityOnHand = 50, AmountOrdered = 20, AmountToReturn = 5, PaybackAmount = 110, ReasonForReturn = "Looking for something else!"});
productModel.ProductItems.Add(new ProductItem() { Name = "Product_2", Type = "B", QuantityOnHand = 50, AmountOrdered = 20, AmountToReturn = 5, PaybackAmount = 110, ReasonForReturn = "Looking for something else!" });
productModel.ProductItems.Add(new ProductItem() { Name = "Product_3", Type = "C", QuantityOnHand = 50, AmountOrdered = 20, AmountToReturn = 5, PaybackAmount = 110, ReasonForReturn = "Looking for something else!" });
productModel.ProductItems.Add(new ProductItem() { Name = "Product_4", Type = "D", QuantityOnHand = 50, AmountOrdered = 20, AmountToReturn = 5, PaybackAmount = 110, ReasonForReturn = "Looking for something else!" });
return productModel;
}`enter code here`
}
View (Product.cshtml)
you need add hidden html helper inside the for loop. Your contain should be under BeginForm helper. Use a button and type should be Summit. After clicking on the button, you will see the all list at controller post action.
#for (int i = 0; i < Model.ProductItems.Count; i++)
#Html.DisplayFor(p => p.ProductItems[i].Name, new { #id = "ItemName_" + i })
#Html.HiddenFor(p => p.ProductItems[i].Name, new { #id = "ItemName_" + i })
</td>
You can add more td as per your need. Here is just one
Related
I want to post data to database but my viewmodel is empty when posting it to the controller, i tried different approaches, but everytime my viewmodel is null.
These are my classes :
public class Player
{
[Key]
public int Id { get; set; }
public string Name{ get; set; }
public string PreName{ get; set; }
}
public class Activitity
{
[Key]
public int Id { get; set; }
public string WhichActivity { get; set; }
public List<Player> Players { get; set; }
}
public class Aanwezigheid
{
[Key]
public int Id { get; set; }
public ReasonEnum Reason{ get; set; }
public int PlayerId{ get; set; }
public Player Player{ get; set; }
public List<Player> Players{ get; set; }
public int ActivityId { get; set; }
}
My View Model :
public class PresenceVM
{
public int PlayerId{ get; set; }
public int ActivityId { get; set; }
public string Name{ get; set; }
public string PreName { get; set; }
public ReasonEnum Reason { get; set; }
}
My HTTPGET for a list of players and I want to put the absence reason with the player in the database.
[HttpGet]
public ActionResult Presence(int id)
{
var sp = _context.Players.ToList();
foreach(Players s in sp)
{
var van = new PresenceVM
{
PlayerId = s.Id,
Name = s.Name,
PreName = s.PreName,
ActivityId = id
};
list.Add(van);
}
return View(list);
}
My HttpPost
[HttpPost]
public ActionResult Presence(List<PresenceVM> list)
{
var sp = _context.Players.ToList();
var list = new List<Presence>();
foreach (Players s in sp)
{
var van = new Aanwezigheid
{
PlayerId = s.Id,
ActivityId = vm.ActivityId,
Reason = vm.Reason
};
list.Add(van);
_context.Presence.Add(van);
//_context.SaveChanges();
}
return RedirectToAction("Index", "Presence");
}
The problem is that my PresenceVm (viewmodel) does not get any data in true my controller. I don't understand why? Is it because of a list? With one item it's easy to post it to database. Maybe multiple items?
Edit 1:
The viewmodel for the Get & Post
#model IEnumerable<....ViewModels.PresenceVM>
#{
ViewBag.Title = "Presence";
}
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.PreName)
</th>
<th>
#Html.DisplayName("Reason")
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.PreName)
</td>
<td>
#Html.EnumDropDownListFor(modelItem => item.Reason, "Present", new { #class = "form-control" })
</td>
</tr>
}
</table>
<form action="/Presences/Presence" method="post">
<div class="form-horizontal form-details">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
You're putting the form scope in wrong place (only include submit button). The correct way should include all properties you want to submit with indexes (since you're using IEnumerable<PresenceVM>, like this example:
<form action="/Presences/Presence" method="post">
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.PreName)
</th>
<th>
#Html.DisplayName("Reason")
</th>
</tr>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.EditorFor(modelItem => item[i].Name)
</td>
<td>
#Html.EditorFor(modelItem => item[i].PreName)
</td>
<td>
#Html.EnumDropDownListFor(modelItem => item[i].Reason, "Present", new { #class = "form-control" })
</td>
</tr>
}
</table>
<div class="form-horizontal form-details">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
Note that if you want to allow user input, you need to change all DisplayFor into EditorFor.
Your Presence method is returning an object that does not exist (list).
It must return the view model if you want to use it in the post method.
[HttpGet]
public ActionResult Presence(int id)
{
List<PresenceVM> model = context.Players.Select(u => new PresenceVM
{
PlayerId = s.Id,
Name = s.Name,
PreName = s.PreName,
ActivityId = id
}).ToList();
return View(model);
}
Seems that you don't use the Form tag
VIEW
#model MyViewModel
#using (Html.BeginForm(("Presence"))
{
#Html.AntiForgeryToken()
//divs
<div class="form-horizontal form-details">
<input type="submit" value="Save" class="btn btn-default" />
</div>
}
And it's better to pass a Model than a list of Model
VIEWMODEL
public class MyViewModel{
public IList<PresenceVM> MyList {get;set;}
}
CONTROLLER
public ActionResult Presence(MyViewModel xxx)
{
//whatever
}
I have an Attendance program in which I want to assign Students to AttendanceTakers. I am using a table where the headers are the AttendanceTakers and the rows are Students and each cell has a RadioButton. It is basically a double array of RadioButtons. My problem is I can't get it to post.
My AttendanceTaker class
public class SessionAttendanceTaker
{
public int Id { get; set; }
[ForeignKey("Session")]
public int SessionId { get; set; }
public Session Session { get; set; }
[Display(Name="Attendance Taker")]
[ForeignKey("User")]
public string AttendanceTakerId { get; set; }
[Display(Name = "Attendance Taker")]
public User User { get; set; }
public List<Student> Students { get; set; }
}
And the Student that is in the course class
public class StudentSession
{
public int Id { get; set; }
[ForeignKey("Session")]
[DisplayName("Session")]
public int SessionId { get; set; }
public Session Session { get; set; }
[ForeignKey("Student")]
[DisplayName("Student")]
public int StudentId { get; set; }
public Student Student { get; set; }
[DisplayName("Credits Awarded")]
public int Credit { get; set; }
}
Student class
public class Student
{
public int Id { get; set; }
[ForeignKey("User")]
public string UserId { get; set; }
[DisplayName("Name")]
public virtual User user { get; set; }
public Student()
{
}
}
The View
#using (Html.BeginForm())
{
<div class="form-horizontal">
<table>
<thead>
<tr>
<th> Name </th>
#{
foreach (var attendanceTaker in Model.SessionAttendanceTakers)
{
<th>#attendanceTaker.User.LastName, #attendanceTaker.User.FirstName </th>
}
}
</tr>
</thead>
<tbody>
#{
//See https://stackoverflow.com/questions/7667495/mvc-radiobuttons-in-foreach to try and clean the foreach
foreach (var studentSession in Model.StudentSessions)
{
<tr>
<td>
#studentSession.Student.User.LastName, #studentSession.Student.User.FirstName
</td>
#foreach (var attendanceTaker in Model.SessionAttendanceTakers)
{
#Html.EditorFor(Model => Model.SessionAttendanceTakers, "StudentsToAttendanceTakersModel", "" + studentSession.StudentId, new { htmlAttributes = new { #class = "form-control" } })
}
</tr>
}
}
</tbody>
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Assign" class="btn btn-default" />
</div>
</div>
</div>
}
and EditorTemplate
#model IEnumerable<SessionAttendanceTaker>
#using Attendance.Models
<td>
#Html.RadioButtonFor(model => model, new { htmlAttributes = new { #class = "form-control" } })
</td>
As an aside I would love to get rid of the foreaches as per this post but since I don't know how many attendance takers or students there will be until runtime I can't figure out how to do that besides for just moving them to the Editor and I don't see a point to that.
Also the Controller
[HttpPost]
public ActionResult Assign(StudentsToAttendanceTakersModel model)
{
return RedirectToAction("Index");
}
I have a breakpoint on the return and the attendanceTakers is null and Student sessions has a count of 0.
Additionally, using FormCollection
public ActionResult Assign(FormCollection o)
only gives me the Students who's RadioButton was clicked but not the AttendanceTaker. If more info is needed let me know. Thanks.
EDIT
Model
public class StudentsToAttendanceTakersModel
{
public IEnumerable<StudentSession> StudentSessions { get; set; }
public IEnumerable<SessionAttendanceTaker> SessionAttendanceTakers { get; set; }
public StudentsToAttendanceTakersModel() { }
}
You're creating radio buttons which do not relate to your model, and you're trying to bind them to a complex object (SessionAttendanceTaker) - a radio button posts back a simple value (and you are not even giving the radio buttons a valid value - the 2nd parameter of RadioButtonFor() is the value).
You are editing data, so you should start by creating view models which represent what you want to display in the view.
public class StudentVM
{
public int ID { get; set; }
public string Name { get; set; }
[Required(ErrorMessage = "Please select an attendance taker")]
public int? SelectedAttendanceTaker { get; set; }
}
public class AttendanceTakerVM
{
public int ID { get; set; }
public string Name { get; set; }
}
public class StudentAttendanceTakersVM
{
public List<StudentVM> Students { get; set }
public IEnumerable<AttendanceTakerVM> AttendanceTakers { get; set; }
}
So that your view will be
#model StudentAttendanceTakersVM
....
#using (Html.BeginForm())
{
<table>
<thead>
<tr>
<th>Student</th>
#foreach(var taker in Model.AttendanceTakers)
{
<th>#taker.Name</th>
}
<th></th>
</tr>
</thead>
<tbody>
#for(int i = 0; i < Model.Students.Count; i++)
{
<tr>
<td>
#Model.Students[i].Name
#Html.HiddenFor(m => m.Students[i].ID)
#Html.HiddenFor(m => m.Students[i].Name)
</td>
#foreach(var taker in Model.AttendanceTakers)
{
<td>#Html.RadioButtonFor(m => m.Students[i].SelectedAttendanceTaker, taker.ID, new { #class = "form-control" })</td>
}
<td>#Html.ValidationMessageFor(m => m.Students[i].SelectedAttendanceTaker)</td>
</tr>
}
</tbody>
</table>
<input type="submit" ... />
}
Your GET method will then initialize an instance of you view model and pass it to the view, for example, for a 'Create' method
public ActionResult Create()
{
var students = db.Students.Select(x => new StudentVM
{
ID = x.Id,
Name = x.User.FirstName + " " + x.User.LastName // adjust as required
}).ToList();
var attendanceTakers = db.SessionAttendanceTakers.Select(x => new AttendanceTakerVM
{
ID = x.Id,
Name = x.User.FirstName + " " + x.User.LastName // adjust as required
});
StudentAttendanceTakersVM model = new StudentAttendanceTakersVM
{
Students = students,
AttendanceTakers = attendanceTakers
};
return View(model);
}
And the POST method will be
public ActionResult Create(StudentAttendanceTakersVM model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// loop through model.Students to get the ID of the Student and its selected AttendanceTaker
// initialize the data models and save to the database
return RedirectToAction("Index");
}
I am trying to get my partial view to display an object name as it iterates through a collection. This is no problem when I refresh the original page but as soon as I do an AJAX post and try to return the new object to the partial view, it cannot find a specific object.
I get a null object error on the FeeTypes object which should be included in the members object as Members.Fees(whateverno).FeeTypesG
Also the ajax post does not refresh the div on success because it never gets success back (or im doing it wrong) NOTE: It still posts everything correctly to the database and saves fine.
Models
public class Members
{
[Key]
public int MemberNo { get; set; }
[Display(Name = "Member Fees")]
public virtual ICollection<Fees> Fees { get; set; }
}
public class Fees
{
[Key]
public int FeeNo { get; set; }
public virtual FeeTypes FeeType { get; set; }
[Display(Name = "Fee Type")]
public int FeeTypesId { get; set; }
[Display(Name = "Frequency of Fee")]
public FeeOccurence FeeOccurence { get; set; }
[Display(Name = "Fee Amount")]
public float FeeAmount { get; set; }
[Display(Name = "Fee Status")]
public FeeStatus FeeStatus { get; set; }
[Display(Name = "Date received (for billing)")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? FeeDate { get; set; }
public virtual Members Members { get; set; }
public int MemberNo { get; set; }
}
public class FeeTypes
{
public int Id { get; set; }
[Display(Name = "Fee Name")]
public string FeeTypeName { get; set; }
}
Controller Action
public ActionResult AddFees(Fees fees)
{
string result;
Members members = db.Members.Find(fees.MemberNo);
ViewBag.Fees = db.Fees
.Include(x => x.FeeType)
.Where(x => x.Members.MemberNo.Equals(x.MemberNo));
ViewBag.FeeTypesId = new SelectList(db.FeeTypes, "Id", "FeeTypeName");
if (ModelState.IsValid)
{
db.Fees.Add(fees);
db.SaveChanges();
return PartialView("~/Views/Members/_MemberDetails.cshtml", members);
}
ViewBag.MemberNo = new SelectList(db.Members, "MemberNo", "FirstName", fees.MemberNo);
result = "Something went wrong!";
return Json(result, JsonRequestBehavior.AllowGet);
}
AJAX Post
saveBtn.click(function () {
var token = $('[name=__RequestVerificationToken]').val();
var postData = {
__RequestVerificationToken: token,
FeeOccurence: feeOccField.val(),
FeeAmount: amountField.val(),
FeeStatus: statusField.val(),
FeeTypesId: typeField.val(),
FeeDate: dateField.val(),
MemberNo: memberNo
};
$.ajax({
url: '/Members/AddFees',
type: 'POST',
data: postData,
success: function (members) {
alert(result);
$("#details").html(members);
},
error: function (result) {
alert(result);
},
traditional: true
});
Partial view
#using AccPortal.Models
#model AccPortal.Models.Members
<h5 class="md-fees-title">Fees</h5>
<table cellpadding="0" cellspacing="0" class="md-fees-table">
<thead>
<tr>
<th>#Html.LabelFor(model => model.Fees.First().FeeDate)</th>
<th>#Html.LabelFor(model => model.Fees.First().FeeOccurence)</th>
<th>#Html.LabelFor(model => model.Fees.First().FeeTypesId)</th>
<th>#Html.LabelFor(model => model.Fees.First().FeeStatus)</th>
<th>#Html.LabelFor(model => model.Fees.First().FeeAmount)</th>
<th></th>
</tr>
</thead>
<tbody>
#{ int i = 0; }
#foreach (var item in Model.Fees)
{
<tr data-id="#i">
#Html.HiddenFor(model => model.Fees.ElementAt(i).FeeNo, new { #class = "md-fee-value", name = "md-fee-id", data_type = "testid", id = "testid" })
<td class="md-fee-value" data-type="date">#String.Format("{0:d}", item.FeeDate)</td>
<td class="md-fee-value" data-type="occ">#item.FeeOccurence.GetDisplayName()</td>
//ERROR HAPPENS ON THE NEXT LINE WHEN IT CANT FIND FEETYPES
<td class="md-fee-value" data-type="type">#item.FeeType.FeeTypeName</td>
<td class="md-fee-value" data-type="status">#item.FeeStatus</td>
<td class="md-fee-value" data-type="amount">#item.FeeAmount</td>
<td>
<button type="button" class="md-button md-button--edit" title="edit">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
</button>
<button type="button" class="md-button md-button--remove" title="remove">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</td>
</tr>
i++;
}
</tbody>
Top level view
#using AccPortal.Models
#using Newtonsoft.Json
#model AccPortal.Models.Members
#{
ViewBag.Title = "Details";
#Styles.Render("~/Content/jqueryui")
}
<h2>Details</h2>
<div>
<h4>Members Details</h4>
<hr />
</div>
<div class="row">
<div class="col-md-7 md-fees" id ="details">
#Html.Partial("_MemberDetails")
</div>
</div>
The problem was with lazy loading in the end.
I was able to get the Fees to repopulate the bound Members.Fees.FeeType by adding
members = db.Members.Find(fees.MemberNo);
members.Fees = db.Fees.Include(x => x.FeeType).Where(x => x.Members.MemberNo.Equals(x.MemberNo)).ToList();
C#, .Net 4.5, MVC 5
Referring to XX1 and XX2 below (Main View):
The object is initialized in the main controller. (Both the header and the Detial.)
I have added breakpoints at both XX1 and XX2 to confirm that that the initialized values are still there.
No problem with XX1. The initialized values are there and it is
passed to and received by the controller.
XX2 have a problem. The initialized values are still there and is
passed to, but a null object is somehow received by, the controller.
Why do the controller for the detail not pick up the passed parameters for it.
Model:
public class SampleNonRoutine
{
public HeaderNonRoutine SampleHeader { get; set; }
public List<DetailNonRoutine> SampleDetail { get; set; }
public string Comments { get; set; }
}
public class HeaderNonRoutine
{
public string Division { get; set; }
public string Name { get; set; }
public string Telephone { get; set; }
[DisplayName("Sample Title")]
public string SampleTitle { get; set; }
[DisplayName("Retain Sample for")]
public int RetainSample { get; set; }
}
public class DetailNonRoutine
{
public int ID { get; set; }
[DisplayName("Sample Reference #")]
public string SampleReference { get; set; }
[DisplayName("Sample Test")]
public string SamplesTested { get; set; }
[DisplayName("Sample Assays")]
public string SampleAssays { get; set; }
}
Controller:
For Parent View
public ActionResult NonRoutineSamples(string SaveSend)
{
SampleNonRoutine sample = new SampleNonRoutine();
sample.SampleHeader = new HeaderNonRoutine();
sample.SampleDetail = new List<DetailNonRoutine>();
sample.Comments = "Toets";
for (int i = 0; i < 10; i++)
{
sample.SampleDetail.Add(new DetailNonRoutine { ID = i + 1, SampleReference = "", SamplesTested = "", SampleAssays = "" });
}
return View(sample);
}
For Partial Views:
Header (Partial View):
public ActionResult _HeaderNonRoutineSamples(HeaderNonRoutine model)
{
//...some code
PersonDetail pDetail = _db.ListPerson(_MePerson.First().Number.ToString());
model.Name = pDetail.Name + " " + pDetail.Surname;
model.Telephone = pDetail.PhoneWork;
model.Division = pDetail.Division;
model.RetainSample = 30;
return PartialView(model);
}
Detail:
public ActionResult _DetailNonRoutineSamples(List<DetailNonRoutine> model)
{
return PartialView(model);
}
Views:
Main
#model LaboratorySampleRegistration.Models.SampleNonRoutine
#{
ViewBag.Title = "NonRoutineSamples";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h4>Non-Routine Samples</h4>
<table>
<tr>
<td>
#Html.Action("_HeaderNonRoutineSamples", "Home", Model.SampleHeader) XX1
</td>
</tr>
<tr>
<td>
#Html.Action("_DetailNonRoutineSamples", "Home", Model.SampleDetail) XX2
</td>
</tr>
<tr>
<td>
<div>
#Html.LabelFor(model => model.Comments, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
<span>
#Html.TextAreaFor(model => model.Comments, new { #class = "SampleRoutineComments" })
#Html.ValidationMessageFor(model => model.Comments, "", new { #class = "text-danger" })
</span>
</div>
</div>
</td>
</tr>
<tr>
<td>
<hr style="border-top:1px solid black !important;" />
<p>
<input id="SaveSend" name="SaveSend" type="submit" value="Send to Laboratory" class="btn btn-default" />
</p>
</td>
</tr>
</table>
}
Would like to create a similar ticketing system.
Having difficulty on how the ticket creator can add new comment.
In the current code below, I am adding new record in the collection and display it as editable. However, it does not bind the whole model, only the hidden idCR.
I thought of additional member in the CRCase model for handling the new comment.e.g. public CRParticipation NewCRParticipantion {get;set;} but I received Invalid Column error because it does not exist in the table.
Any guidance is highly appreciated.
Model:
public class CRCase
{
[Key]
public int idCR { get; set; }
public string CRNo { get; set; }
public DateTime SubmittedDate { get; set; }
public string Responsible { get; set; }
public virtual ICollection<CRParticipation> CRParticipations { get; set; }
}
public class CRParticipation
{
[Key]
public int IdCRParticipation { get; set; }
public string CRStatus { get; set; }
public DateTime UpdatedDate { get; set; }
public string Comments { get; set; }
public int CR { get; set; }
[ForeignKey("CR")]
public CRCase CRCase { get; set; }
}
Controller:
public ActionResult Details(int id = 0)
{
CRCase crcase = db.CRCases.Find(id);
if (crcase == null)
{
return HttpNotFound();
}
else
{
//adding new record for new comments. might not be the proper approach.
crcase.CRParticipations.Add(new CRParticipation());
}
return View(crcase);
}
[HttpPost]
public ActionResult NewComment(CRCase crcase)
{
if (ModelState.IsValid)
{
//code here
return RedirectToAction("Details", new { id = crcase.idCR});
}
return View(crcase);
}
Display and Adding new comment View:
#model CRManagement1.Models.CRCase
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
#using (Html.BeginForm("NewComment", "CRCase")) {
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.idCR)
<fieldset>
<legend>CRCase</legend>
<div class="display-label">
#Html.DisplayNameFor(model => model.CRReferenceNo)
</div>
<!-- more fields here t display -->
<div class="display-field">
<table>
<tr>
<th>CRStatus</th>
<th>UpdatedDate</th>
<th>Comments</th>
</tr>
#foreach (var item in Model.CRParticipations)
{
<tr>
#if( item.IdCRParticipation != 0 )
{
<td>
#Html.DisplayFor(modelItem => item.CRStatus)
</td>
<td>
#Html.DisplayFor(modelItem => item.UpdatedDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments)
</td>
}
else
{
<td colspan="3" class="editor-field">
#Html.EditorFor(model => model.CRParticipations.Last().Comments)
#Html.ValidationMessageFor(model => model.CRParticipations.Last().Comments)
</td>
}
</tr>
}
</table>
</div>
</fieldset>
<p>
<input type="submit" value="Post" />
</p>
}
<p>
#Html.ActionLink("Back to List", "Index")
</p>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
View Output. If you can notice the new comment is inputted but it will not be bonded in the model when "Post" button is clicked.