Empty Enumeration in post method - asp.net-mvc-3

I have this view
#model IEnumerable<ViewModelRound2>
... <snip> ...
#{
using (Html.BeginForm(new { round1Ring3Bids = Model }))
{
if (Model != null && Model.Count() > 0)
{
... <snip> ...
#for (var x = 0; x < Model.Count(); x++)
{
ViewModelRound2 viewModelRound2 = Model.ElementAt(x);
Bid bid = viewModelRound2.Bid;
string userName = #bid.User.Invitation.Where(i => i.AuctionId == bid.Lot.Lot_Auction_ID).First().User.User_Username;
<tr>
<td>
#userName
</td>
<td>
#bid.Bid_Value
</td>
<td>
#Html.EditorFor(c => c.ElementAt(x).SelectedForRound2)
</td>
</tr>
}
</table>
<div class="buttonwrapper2">
<input type="submit" value="Select"/>
</div>
}
}
}
I have a post method that this goes to when the submit button is hit
[HttpPost]
public ActionResult Round2Manager(IEnumerable<ViewModelRound2> round1Ring3Bids)
Problem is that the enumeration is always empty. Why is this?

Problem is that the enumeration is always empty. Why is this?
Because you are not respecting the wire format that the default model binder expects to bind collections.
The following:
#Html.EditorFor(c => c.ElementAt(x).SelectedForRound2)
generates absolutely wrong names for your input fields.
I would recommend you using editor templates to avoid those kind of problems:
#model IEnumerable<ViewModelRound2>
#using (Html.BeginForm())
{
if (Model != null && Model.Count() > 0)
{
<table>
#Html.EditorForModel()
</table>
<div class="buttonwrapper2">
<input type="submit" value="Select"/>
</div>
}
}
and then define a custom editor template for the ViewModelRound2 type (~/View/Shared/EditorTemplates/ViewModelRound2.cshtml) which will automatically be rendered for each element of this collection:
#model ViewModelRound2
# {
string userName = Model.Bid.User.Invitation.Where(
i => i.AuctionId == Model.Bid.Lot.Lot_Auction_ID
).First().User.User_Username;
}
<tr>
<td>
#userName
</td>
<td>
#Model.Bid.Bid_Value
</td>
<td>
#Html.EditorFor(c => c.SelectedForRound2)
</td>
</tr>
You will now notice how the text input fields have correct names:
name="[0].SelectedForRound2"
name="[1].SelectedForRound2"
name="[2].SelectedForRound2"
...
Compare this with your initial values.

Related

IEnumerable Model from view to Controller is NULL [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 4 years ago.
I am trying to return table values of my view back to the controller to save on db but I keep getting null. I can post the values without problem and bind them to the view.
I cannot understand why, I am using a server side view model.
Is there any way to perform this?
View:
#model IEnumerable<MultiEdit.Models.TableViewModel>
#using (Ajax.BeginForm("Save", "UUTs", new AjaxOptions
{
HttpMethod = "Post",
}, new { id = "tableForm" }))
{
#Html.AntiForgeryToken()
<div class="row" style="padding-top:10px;">
<div class="col-lg-12">
<table class="table table-bordered table-striped ">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.IsChassis)
</th>
<th>
#Html.DisplayNameFor(model => model.Justification)
</th>
</tr>
</thead>
<tbody id="tblMultiEdit">
#foreach(var item in Model)
{
<tr>
<td>
#Html.CheckBoxFor(modelItem => item.CheckIsChassis)
</td>
<td>
#Html.EditorFor(modelItem => item.Justification)
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
Controller:
public void Save(IEnumerable<TableViewModel> vm)
{
DoSomething();
}
You need to iterate through your collection with a for loop and index qualifier. Something like the below. The syntax is not exact but you should be able to see what I mean.
#for(var index = 0; index <= Model.Count - 1; index++)
{
<tr>
<td>
#Html.CheckBoxFor(modelItem => Model[index].CheckIsChassis)
</td>
<td>
#Html.EditorFor(modelItem => Model[index].Justification)
</td>
</tr>
}
This is required so the index can be used to create the unique id's of the Enumerable items and aids model binding
Hope that helps
I resolved it by using IList insead of IEnumerable.
View:
#model IList<MultiEdit.Models.TableViewModel>
#Html.CheckBoxFor(modelItem => modelItem[index].CheckIsChassis, new { #class = "form-control" })
Controller:
public void Save(IList<TableViewModel> vm)
{
var x = vm;
}

AJAX call to delete DB record

I have a page that displays a list of courses for an individual. The page allows a user to delete a course from the selected users course list. When the delete button is clicked, that course should be deleted from the course list and the list of courses should be re-displayed. In my controller I was trying to delete the record, then call the listCourses view (view that initially lists the courses for a user) but when I click the delete button, nothing happens. Below is my code:
View to select a student:
#foreach (var stu in Model)
{
<tr>
<td class="stulisttd">
#stu.Id
</td>
<td class="stulisttd">
#stu.fname
</td>
<td class="stulisttd">
#stu.lname
</td>
<td class="thEditButton">
#using (Ajax.BeginForm("addCourses", "ManageStudentCourses", stuEditCourses))
{
#Html.TextBox("stuId", (string)stu.Id, new { #class = "listCourseText" })
<input type="submit" id="addCourses" name="addCourses" value='Add Courses' class="AllTracksButtons" />
}
</td>
<td class="thEditButton">
#using (Ajax.BeginForm("listCourses", "ManageStudentCourses", stuEditCourses))
{
#Html.TextBox("stuId", (string)stu.Id, new { #class = "listCourseText" })
<input type="submit" value="List Courses" class="AllTracksButtons" id=#stu.Id />
}
</td>
</tr>
}
View that lists the courses for user selected:
#foreach (var course in Model)
{
using (Ajax.BeginForm("deleteCourses", "ManageStudentCourses", stuListEditCourses))
{
<tr class="trCourseList">
<td>
#course.courseAbNum
#Html.TextBox("courseAbNum", (string)course.courseAbNum, new { #class = "editCourseText" })
</td>
<td>
#course.courseDesc
</td>
<td>
#course.status
</td>
<td>
#course.grade
</td>
<td>
#course.credits
</td>
<td>
<input type="submit" value="Delete" class="courseListButtons" id="displayEdit" />
</td>
</tr>
}
deleteCourses controller:
public PartialViewResult deleteCourses(string courseAbNum)
{
KuPlanEntities db = new KuPlanEntities();
var deleteCourse = (from course in db.COURSE_TAKEN
where course.courseAbNum == courseAbNum && course.Id == "000160228"
select course);
foreach (var course in deleteCourse)
{
db.COURSE_TAKEN.Remove(course);
db.SaveChanges();
}
var stuCourses = (from studCourse in db.COURSE_TAKEN
join course in db.COURSEs on studCourse.courseAbNum equals course.courseAbNum
where studCourse.Id == "000160228"
select new courseListViewModel { id = studCourse.Id, courseAbNum = studCourse.courseAbNum, status = studCourse.status, grade = studCourse.grade, courseDesc = course.courseDesc, credits = course.credits });
return PartialView("~/Views/ManageStudentCourses/listCourses.cshtml", stuCourses);
}
I think you're going to have an issue with this code
foreach (var course in deleteCourse)
{
db.COURSE_TAKEN.Remove(course);
db.SaveChanges();
}
You'll likely get the error "Collection was modified; enumeration operation may not execute."
To get around this you can use this hack
while (db.COURSE_TAKEN.Where(x => x.ID == ID).Count() != 0)
{
COURSE_TAKEN course = db.COURSE_TAKEN.Where(x => x.ID == ID).FirstOrDefault();
db.COURSE_TAKEN.Remove(course);
db.SaveChanges();
}
Hope this helps.

How can I make a loop to repeat my method for each item?

there is my issue. In a controller, I have this method which export my view in a file when I click a button.
public ActionResult Export(string searchString, int searchOrder = 0)
{
var user = from m in db.Orders select m;
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.ClientID.Contains(searchString));
}
Response.AddHeader("Content-Type", "application/vnd.ms-excel");
return this.View(user);
}
My Index view :
#model IEnumerable<MyApp.Models.Order>
#{
ViewBag.Title = "Index";
}
<h2>Orders Historic</h2>
<div id="orderDiv">
#using (Html.BeginForm("Export", "Historic", FormMethod.Get))
{
<p>
Generate Order with ClientID :&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
#Html.TextBox("searchString")
<input type="submit" value="GENEREMOI" />
</p>
}
</div>
And my Export view :
#model IEnumerable<KrysGroup.Models.Order>
<table cellpadding="3" cellspacing="3">
<tr>
<td width="12%" align="center">
Client Name/ID
</td>
<td width="15%" align="center">
N° Order
</td>
OTHER TD....
</tr>
#foreach (var item in Model)
{
TimeSpan result = DateTime.Now - item.OrderDate;
if (result.Days < 31)
{
<tr border="1" bgcolor="#Odd">
<td> #Html.DisplayFor(modelItem => item.Username) </td>
<td> #Html.DisplayFor(modelItem => item.OrderId) </td>
<td>
<ul style="list-style-type:none; padding:0; margin:0">
#if (item.OrderDetails != null)
{
foreach (var o in item.OrderDetails)
{
if (o.Pack == null)
{
<li> #Html.DisplayFor(modelItem => o.Product.Name) </li>
}
else
{
<li> <text>Pack</text> #Html.DisplayFor(modelItem => o.Pack.Name) </li>
}
}
}
</ul>
</td>
OTHER TD...
</table>
So, in my view, I inform in a textbox a ClientID and when I click the button, it export in a file all the fields in my table with this ClientID.
I would like to automate this action, that is to say I would like write a method or something for, when I click on the button, it executes this export() method for each clientId it meet in my table.
I hope I was clear enough, sorry for my english..
Thanks for your answers, links, tips whatever.
You can write a partial view typed to a list of Id's that loads when you click the button.
So in the controller you have a method converts what you want and returns a view that is typed to the conversion of your model.
In your main view you have a div that will be populated with a partial view after the click-event of the original button.
#Ajax.ActionLink("Name", "NameOfTheAction", "NameOfTheController",
new { id = itemId },
new AjaxOptions { HttpMethod = "Get", UpdateTargetId = "divInMainView", OnSuccess = "Do Something (js)" },
new { html-props })
How to populate is up to you, in your view

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.

Resources