MVC3 textbox submits null value? - asp.net-mvc-3

I am creating a dynamic list of text boxes. when the user submits the value in the fields come back null. I think I'm missing something.
This is my product model:
public class EnqProduct
{
public string Id { get; set; }
public string Product { get; set; }
public string Quantity { get; set; }
}
This is the page model which includes a list of the above.
public IList<EnqProduct> EnqProduct { get; set; }
This is how I am setting the model:
IList<EnqProduct> items2 = Session["enquiry"] as IList<EnqProduct>;
var EnquiryModel = new Enquiry {
EnqProduct = items2
};
return View(EnquiryModel);
and this is how I display the fields:
foreach (var item in Model.EnqProduct)
{
<tr>
<td>
<span class="editor-field">
#Html.TextBox(item.Id, item.Product)
#Html.ValidationMessageFor(m => m.A1_Enquiry)
</span>
<br><br>
</td>
<td>
<span id = "field" class="editor-field">
#Html.TextBox(item.Id, item.Quantity)
</span>
<br><br>
</td>
</tr>
}
When the user submits the fields go back to the controller null?

I would recommend you using editor templates and replace your foreach loop with the following:
#model Enquiry
<table>
<thead>
<tr>
<th>product name</th>
<th>quantity</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(x => x.EnqProduct)
</tbody>
</table>
and then define an editor template which will automatically be rendered for each element of the EnqProduct collection (~/Views/Shared/EditorTemplates/EnqProduct.cshtml):
#model EnqProduct
<tr>
<td>
#* We include the id of the current item as hidden field *#
#Html.HiddenFor(x => x.Id)
<span class="editor-field">
#Html.EditorFor(x => x.Product)
#Html.ValidationMessageFor(x => x.Product)
</span>
</td>
<td>
<span id="field" class="editor-field">
#Html.EditorFor(x => x.Quantity)
</span>
</td>
</tr>
Now when you submit the form you will get correct values:
public class HomeController: Controller
{
public ActionResult Index()
{
var model = new Enquiry();
model.EnqProduct = ...
return View(model);
}
[HttpPost]
public ActionResult Index(Enquiry model)
{
// the model.EnqProduct will be correctly populated here
...
}
}
As far as the correct wire format that the default model binder expects for your input fields I would recommend you taking a look at the following article. It will allow you to more easily debug problems in the feature when some model is not properly populated. It suffice to look with FireBug and the name of the values being POSTed and you will immediately know whether they are OK or KO.

Related

ASP.NET Core 6 MVC : HTML table to view model collection

Starting up with ASP.NET Core 6 MVC and in my case I have one view which lists few properties of one object and then some other for their children in a editable table (user can edit the values)
View model has the properties and an IEnumerable of the children:
public class MyObjectViewModel
{
public String Id { get; set; }
public String Descr { get; set; }
public IEnumerable<ChildrenObject> Children { get; set; }
public MyObjectViewModel()
{
Children = Enumerable.Empty<ChildrenObject>();
}
public class ChildrenObject
{
public String? Id { get; set; }
public String? Name { get; set; }
}
}
All under the same form:
#using (Html.BeginForm("Save", "Controller", FormMethod.Post))
{
<input type="submit" value="SAVE"/>
<br />
#Html.LabelFor(model => model.Id)
#Html.TextBoxFor(model => model.Id, new { #readonly = "readonly" })
<br />
#Html.LabelFor(model => model.Descr)
#Html.EditorFor(model => model.Descr)
<br />
<table>
<tbody>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
#foreach (var child in Model.Children)
{
<tr>
<td>#child.Id</td>
<td><input class="ef-select" type="text" value="#child.Name"></td>
</tr>
}
</tbody>
</table>
}
So when the button is pressed the data is dumped back to the model to perform the SAVE action in the controller.
All ok for the simple fields (I can get the data in the controller as the view model), but not sure how to accomplish it with the table / children property...
Any simple way without needing to use JS to serialise or pick up the data from the table?
Thanks
If you want to pass id and name of ChildrenObject in table,you can try to add hidden inputs for the Id,and set name attribute for name inputs:
#{var count = 0; }
#foreach (var child in Model.Children)
{
<tr>
<td>
#child.Id
<input value="#child.Id" name="Children[#count].Id" />
</td>
<td><input class="ef-select" type="text" value="#child.Name" name="Children[#count].Name"></td>
</tr>
count++;
}

Error on page: The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies

I get this error on my Details view page:
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.cpd_certificates_65AF30842281867E2F4F6A1026590271109C12A85C8175394F14EF6DE429CBC7', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[cpd.Models.cpd_certificates]'.
This is my controller :
public class Default8Controller : Controller
{
//
// GET: /Default8/
private cpdDbContext db = new cpdDbContext();
public ActionResult Index()
{
return View(db.CPD.ToList());
}
//
// GET: /Default8/Details/5
public ActionResult Details(int id)
{
cpd_certificates cpd_ = db.Cert.Find(id);
return View(cpd_);
}
Below is my Details view:
#model IEnumerable<cpd.Models.cpd_certificates>
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<table>
<tr>
<th>
certificateNo
</th>
<th>
Mark
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.CertificateNo)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mark)
</td>
</tr>
}
</table>
Below is the cpd_certificates model:
public class cpd_certificates
{
[Key]
public int CertificateNo { get; set; }
public int QuizNo { get; set; }
public DateTime? DateReceived { get; set; }
public DateTime? DatePaid { get; set; }
public string Mark { get; set; }
public int? AccreditationNo { get; set; }
public int? ID { get; set; }
public virtual cpd_recipients Recipients { get; set; }
}
I have two models and I can view the list on my Index. I intended that when I click the details link it takes me to details of certificates earned and exams which are in another model/table. So in short two models which have a PK ID for CPD and FK ID on Cert. Index page show just personal information and this page is fine.
When Details is clicked it then shows the other model/table data that is the many certificates of that person.
You should pass the model into the view as the List of IEnumerable entries instead of passing it as a single entry.
In your Controller you want to show one entry details, but in the view, want to show details of all entries.First you should decide what to show.
For showing one entry details, use this:
controller:
public ActionResult Details(int id)
{
cpd_certificates cpd_ = db.Cert.Find(id);
return View(cpd_);
}
view:
#model cpd.Models.cpd_certificates
#{
ViewBag.Title = "Details";}
<h2>Details</h2>
<table>
<tr>
<th>
certificateNo
</th>
<th>
Mark
</th>
<th></th>
</tr>
<tr>
<td>
#Html.DisplayFor(model => model.CertificateNo)
</td>
<td>
#Html.DisplayFor(model => model.Mark)
</td>
</tr>
}
</table>
And when you want to list all of entries, use this:
controller:
public ActionResult List()
{
cpd_certificates cpd_ = db.Cert.ToList();
return View(cpd_);
}
view:
#model IEnumerable<cpd.Models.cpd_certificates>
#{
ViewBag.Title = "List";
}
<h2>List</h2>
<table>
<tr>
<th>
certificateNo
</th>
<th>
Mark
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.CertificateNo)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mark)
</td>
</tr>
}
</table>

EditorTemplate + Model not being returned on POST

I can't seem to figure this out, it is driving me crazy!
Essentially, I have a list of rows I need to display with one drop down list per row.
I have a view model:
public class UserMembershipViewModel:BaseViewModel
{
public List<ProgramMembership> ProgramMembership { get; set; }
}
In my parent view I have, as you can see I am using an editor template which is located in "/Views/Shared/EditorTemplates/ProgramMembership.cshtml":
#using AcnCS.Model
#model AcnCS.Model.ViewModels.User.UserMembershipViewModel
#{
ViewBag.PageHeader = "Membership for " + Model.User.FullName;
ViewBag.PageTitle = "Membership for " + #Model.User.FullName;
ViewBag.HideNav = true;
}
#if (Model.ProgramMembership != null)
{
<div class="row-fluid">
<div class="span12">
<div id="permissions">
#using (Html.BeginForm())
{
<table class="table table-bordered">
<thead>
<tr>
<td>Program</td>
<td>Effective Membership?</td>
<td>Permission Type</td>
</tr>
</thead>
#Html.EditorFor(m => Model.ProgramMembership, "ProgramMembership")
</table>
<input type="submit" class="btn btn-primary" value="Save Changes"/>
}
</div>
</div>
</div>
}
My Editor template (ProgramMembership.cshtml) is:
#using AcnCS.Model
#model List<AcnCS.Model.ProgramMembership>
#foreach(ProgramMembership membership in Model)
{
<tr>
<td>#membership.ProgramName</td>
<td>
#if (membership.IsMember)
{
<span class="label label-success">#membership.IsMember</span>
}
else
{
#membership.IsMember
}
</td>
<td>#Html.DropDownListFor(x => membership.PermissionType, membership.PermissionTypes)</td>
</tr>
}
Everything is being displayed properly, but when I submit, my model object is null, even the ProgramMembership property in the model is null:
[HttpPost]
public ActionResult Membership(UserMembershipViewModel model)
{
// model IS NULL!!
return View(model);
}
Any help would be greatly appreciated!
I would pluralize the Property name since it is a collection, for better readability
public class UserMembershipViewModel:BaseViewModel
{
public List<ProgramMembership> ProgramMemberships { get; set; }
}
and you dont need a Loop inside your EditorTemplate file
#model AcnCS.Model.ProgramMembership
<tr>
<td>#membership.ProgramName</td>
<td>
#if (membership.IsMember)
{
<span class="label label-success">#membership.IsMember</span>
}
else
{
#membership.IsMember
}
</td>
<td>#Html.DropDownListFor(x => membership.PermissionType, membership.PermissionTypes)</td>
</tr>
In your main view,call your EditorTemplate like this
#Html.EditorFor(m=>m.ProgramMemberships)

Posting to a list<modeltype> MVC3

I am trying to get my view to post a List back to the action however it keeps coming in as null.
So my Model has a List of WeightEntry objects.
Exercise Model
public class Exercise
{
public List<WeightEntry> Entries { get; set; }
public int ExerciseID { get; set; }
public int ExerciseName { get; set; }
}
WeightEntry Model
public class WeightEntry
{
public int ID { get; set; }
public int Weight { get; set; }
public int Repetition { get; set; }
}
My View contains the ExerciseName and a forloop of WeightEntry objects
#model Mymvc.ViewModels.Exercise
...
<span>#Model.ExerciseName</span>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<table class="left weight-record">
<tr>
<th>Reps</th>
<th>Weight</th>
</tr>
#foreach (var item in Model.Entries)
{
<tr>
<td>
#Html.EditorFor(x => item.Repetition)
</td>
<td>
#Html.EditorFor(x => item.Weight)
</td>
</tr>
}
</table>
<input type="submit" value="Save" />
}
The Controller Action (Post) Does nothing at the moment. I am just trying to get the binding working before I add the save code.
[HttpPost]
public ActionResult WeightEntry(Exercise exercise)
{
try
{
//Add code here to save and check isvalid
return View(exercise);
}
catch
{
return View(exercise);
}
}
I have seen a few little tricks with adding a numerator to the form elements' names used in MVC2 but I was wondering if MVC3 was any different? I was hoping it would all bind nicely with ID's being 0 or null but instead the whole List is null when I inspect it after the form posts. Any help is appreciated.
Thanks.
Replace the following loop:
#foreach (var item in Model.Entries)
{
<tr>
<td>
#Html.EditorFor(x => item.Repetition)
</td>
<td>
#Html.EditorFor(x => item.Weight)
</td>
</tr>
}
with:
#for (var i = 0; i < Model.Entries.Count; i++)
{
<tr>
<td>
#Html.EditorFor(x => x.Entries[i].Repetition)
</td>
<td>
#Html.EditorFor(x => x.Entries[i].Weight)
</td>
</tr>
}
or even better, use editor templates and replace the loop with:
#Html.EditorFor(x => x.Entries)
and then define a custom editor template that will automatically be rendered for each element of the Entries collection (~/Views/Shared/EditorTemplates/WeightEntry.cshtml):
#model WeightEntry
<tr>
<td>
#Html.EditorFor(x => x.Repetition)
</td>
<td>
#Html.EditorFor(x => x.Weight)
</td>
</tr>
The the generated input elements will have correct names and you will be able to successfully fetch them back in your POST action.

MVC3 The model item passed into the dictionary is of type '_320.Models.MyViewModel', but

I am passing a viewmodel into a view containing a foreach loop. This viewmodel contains two lists. These lists are filled using Linq.
With the following code, I get the following error: The model item passed into the dictionary is of type '_320.Models.MyViewModel', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[_320.Models.MyViewModel]'.
I want to reach properties contained in the two lists in the ViewModel in my view's foreach loop.
UPDATE
I have been able to display the view by modifying the end of my controller code to:
List<MyViewModel> MyList = new List<MyViewModel>();
MyList.Add(_myViewModel);
return View(MyList);
However, it is an empty view with nothing but headers. When I attempt to change my fields in my view from something like #Html.DisplayFor(modelItem => item.rx.Rx_ID) to #Html.DisplayFor (modelItem => item.Rxes.rx.Rx_ID) it is labeled red. Is it impossible to access a property located that far down in a list?
END OF UPDATE
Model
public class MyViewModel
{
public Patient patient { get; set; }
public Rx rx { get; set; }
public Fill fill { get; set; }
public List<Rx> Rxes { get; set; }
public List<Fill> Fills { get; set; }
Controller
public ActionResult AllFilled()
{
MyViewModel _myViewModel = new MyViewModel();
List<Fill> FillList = db.Fills.Where(p => p.Status == "Filled").ToList();
List<Rx> RxList = new List<Rx>();
Rx myRx = new Rx();
foreach (var item in FillList)
{
myRx = db.Rxes.Single(p => p.Rx_ID == item.Rx_ID);
RxList.Add(myRx);
}
_myViewModel.Fills = FillList;
_myViewModel.Rxes = RxList;
return View(_myViewModel);
}
}
View
#model IEnumerable<_320.Models.MyViewModel>
#{
ViewBag.Title = "AllFilled";
}
<h2>AllFilled</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
NDC
</th>
<th>
Rx_ID
</th>
<th>
Fill_ID
</th>
<th>
Status
</th>
<th>
Filled Date
</th>
<th>
Filled By
</th>
<th></th>
</tr>
{
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.rx.NDC)
</td>
<td>
#Html.DisplayFor(modelItem => item.rx.Rx_ID)
</td>
<td>
#Html.DisplayFor(modelItem =>item.fill.Fill_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.fill.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.fill.Filled_Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.fill.Filled_By)
</td>
<td>
#Html.ActionLink("Details", "Details", new { id=item.rx.Rx_ID })
</td>
</tr>
}
</table>
Your view is expecting a model of type IEnumerable<_320.Models.MyViewModel> due to the first line in the view.
#model IEnumerable<_320.Models.MyViewModel>
If you want to use a model object of type MyViewModel (as coded in your controller), change this line to
#model _320.Models.MyViewModel

Resources