Can't get the binding object in a Form - asp.net-mvc-4

In a ASP.NET MVC 4 project, I create a Model Class named Task with its CRUD and in the index page wich list the tasks I need to modify each line separatly. So I create a form in each line. But when I submit a line I don't get the object Task in the action in the controller.
Here is the code :
Thanks
Controller
public ActionResult Index()
{
ViewBag.projectVersionList = this.getProjectVersionList();
ViewBag.taskTypeList = this.getTaskTypeList();
ViewBag.durationList = this.getDurationList();
return View(db.Tasks.ToList());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Task task)//task est instancié mais les propriétées sont vides
{
task.User = db.UserProfiles.Find(WebSecurity.CurrentUserId);
if (ModelState.IsValid)
{
db.Entry(task).State = EntityState.Modified;
db.SaveChanges();
}
return View(task);
}
View
#model IEnumerable<TimeSheet.Models.Task>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<div class="responsive-table-line">
<table class="table table-striped" data-card-view="true">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Date)
</th>
<th>
#Html.DisplayNameFor(model => model.UserId)
</th>
<th>
#Html.DisplayNameFor(model => model.ProjectVersionId)
</th>
<th>
#Html.DisplayNameFor(model => model.TaskTypeId)
</th>
<th>
#Html.DisplayNameFor(model => model.Duration)
</th>
<th>
#Html.DisplayNameFor(model => model.Accomplished)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
#Html.EditorFor(m => item)
}
</tbody>
</table>
</div>
Editor Template :
#model TimeSheet.Models.Task
#using (Ajax.BeginForm(new AjaxOptions
{
HttpMethod = "POST"
}))
{
#Html.AntiForgeryToken()
<tr>
<td data-title="#Html.DisplayNameFor(model => model.Date)">
#Html.HiddenFor(m => m.TaskId)
<div class="form-group">
#Html.TextBoxFor(m => m.Date, new { #class = "datefield form-control", type = "date" })
</div>
</td>
<td data-title="#Html.DisplayNameFor(model => model.UserId)">
#Html.DisplayFor(m => m.User.UserName)
</td>
<td data-title="#Html.DisplayNameFor(model => model.ProjectVersionId)">
<div class="form-group">
#Html.DropDownListFor(m => m.ProjectVersionId, (IEnumerable<SelectListItem>)ViewBag.projectVersionList, new { #class = "form-control" })
</div>
</td>
<td data-title="#Html.DisplayNameFor(model => model.TaskTypeId)">
<div class="form-group">
#Html.DropDownListFor(m => m.TaskTypeId, (IEnumerable<SelectListItem>)ViewBag.taskTypeList, new { #class = "form-control" })
</div>
</td>
<td data-title="#Html.DisplayNameFor(model => model.Duration)">
<div class="form-group">
#Html.DropDownListFor(m => m.Duration, (IEnumerable<SelectListItem>)ViewBag.durationList, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Duration)
</div>
</td>
<td data-title="#Html.DisplayNameFor(model => model.Accomplished)">
#Html.CheckBoxFor(m => m.Accomplished)
</td>
<td data-title="">
<button type="submit" class="btn btn-default glyphicon glyphicon-floppy-disk" aria-label="Left Align"></button>
#Html.ActionLink(" ", "Edit", new { id = Model.TaskId }, new { #class = "btn btn-default glyphicon glyphicon-edit" })
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-align-left" aria-hidden="true"> #Html.ActionLink(" ", "Details", new { id = Model.TaskId })</span>
</button>
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-trash" aria-hidden="true"> #Html.ActionLink(" ", "Delete", new { id = Model.TaskId })</span>
</button>
</td>
</tr>
}

Thanks ! I've found the pb : The fields in each forms are names "items.[propertyName]" instead of "[propertyName]".I replace in the view item by model like this
#foreach (var model in Model)
{
#Html.EditorFor(m => model)
}
And in EditorTemplace m by model
model => model.Accomplished
Thanks!

Related

Master Detail not showing details table in modal popup - ASP.NET Core

I am doing CRUD operations on a Master Detail models Team and TeamMember using modal popup. I followed this post to perform the Create operation and it is ok, now i am doing the Detail operation:
TeamController:
public IActionResult Detail(int id)
{
Team team = _dbcontext.Team
.Include(a => a.TeamMembers)
.Where(e => e.TeamId == id).FirstOrDefault();
return PartialView("_DetailTeamPartialView", team);
}
Index.cshtml detail button:
<button class="btn btn-success" data-toggle="modal" data-target="#("#DetailTeam-"+item.TeamId)" data-url="#Url.Action($"Detail/{item.TeamId}")">Detail</button>
#await Html.PartialAsync("_DetailTeamPartialView", item)
_DetailTeamPartialView.cshtml:
#model Team
#{
ViewData["Title"] = "_DetailTeamPartialView";
}
<div class="modal fade" role="dialog" tabindex="-1" id="#("DetailTeam-"+Model.TeamId)" aria-labelledby="DetailTeamLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-xl modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Detail Team</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="javascript:window.location.reload()">
<span aria-hidden="true">×</span>
</button>
</div>
<div>
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.TeamName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.TeamName)
</dd>
.......
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.TeamMembers)
</dt>
<dd class="col-sm-10">
<table class="table table-bordered table-sm">
<thead>
<tr>
<th>Member name</th>
<th>Birth date</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.TeamMembers.Count; i++)
{
<tr>
<td>
<input asp-for="#Model.TeamMembers[i].MemberName" class="form-control-plaintext" readonly />
</td>
<td>
<input asp-for="#Model.TeamMembers[i].BirthDate" class="form-control-plaintext" readonly />
</td>
</tr>
}
</tbody>
</table>
</dd>
</dl>
</div>
</div>
</div>
</div>
This code displays only team details and doesn't show the TeamMember details. Any help??
EDIT
these are the classes:
public class Team
{
[Key]
public int TeamId { get; set; }
[Required]
public string TeamName { get; set; }
public virtual List<TeamMember> TeamMembers { get; set; } = new List<TeamMember>();
}
public class TeamMember
{
[Key]
public int TeamMemberId { get; set; }
[Required]
public string MemberName{ get; set; }
[Required]
public DateTime BirthDate{ get; set; }
[ForeignKey("TeamId")]
public int TeamId { get; set; }
public virtual Team Team{ get; set; }
}
'Model.TeamMembers.Count' in '#for (int i = 0; i < Model.TeamMembers.Count; i++)' return 0 why??
Master Detail not showing details table in modal popup - ASP.NET Core
I have gone through your shared code snippet between the line altough, you haven't shared your index page's code that certainly playing important role here. Nontheless, I tried to visualize what you are trying to achieve.
Expected Behaviour:
From the shared code, I have managed to build above output therefore, the expected behaviour might be while clicking on details button on the team's list which is the index page should display the details list of all the team member of that particular team. If that is the business scenario, then I would say, your approach were wrong and you are doing mess of course here thus, follow the steps below which will help to resolve your issue.
Database:
Note: Models would be same as yours. So not repeating that part.
Controller:
public class TeamController : Controller
{
private readonly ApplicationDbContext _context;
private readonly IWebHostEnvironment _environment;
public TeamController(IWebHostEnvironment environment, ApplicationDbContext context)
{
_environment = environment;
_context = context;
}
public IActionResult Index()
{
var teamList = _context.Teams.Include(a => a.TeamMembers).ToList();
return View(teamList);
}
}
Note: You are doing the mess here as you are using another details action for the _DetailTeamPartialView which is complete Irelevant here. Only Index action is capable here what you are trying to achieve. Just need to use Include(a => a.TeamMembers) which the action.
View Of Index()
#model IEnumerable<DotNet6MVCWebApp.Models.Team>
#{
ViewData["Title"] = "Index";
}
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.TeamId)
</th>
<th>
#Html.DisplayNameFor(model => model.TeamName)
</th>
<th>
Member Details
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.TeamId)
</td>
<td>
#Html.DisplayFor(modelItem => item.TeamName)
</td>
<td>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#("#DetailTeam-"+item.TeamId)">Detail</button>
#await Html.PartialAsync("_DetailTeamPartialView", item)
</td>
</tr>
}
</tbody>
</table>
_DetailTeamPartialView
Though, your _DetailTeamPartialView is alrigh and no vital issue has not seen,
#model DotNet6MVCWebApp.Models.Team
#{
ViewData["Title"] = "_DetailTeamPartialView";
}
<div class="modal fade" role="dialog" tabindex="-1" id="#("DetailTeam-"+Model.TeamId)" aria-labelledby="DetailTeamLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-xl modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Detail Team</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="javascript:window.location.reload()">
<span aria-hidden="true">×</span>
</button>
</div>
<div>
<dl class="row">
<div style="margin-left:10px">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.TeamName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.TeamName)
</dd>
.......
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.TeamMembers)
</dt>
<dd class="col-sm-10">
<table class="table table-bordered table-sm">
<thead>
<tr>
<th>Member name</th>
<th>Birth date</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.TeamMembers.Count; i++)
{
<tr>
<td>
<input asp-for="#Model.TeamMembers[i].MemberName" class="form-control-plaintext" readonly />
</td>
<td>
<input asp-for="#Model.TeamMembers[i].BirthDate" class="form-control-plaintext" readonly />
</td>
</tr>
}
</tbody>
</table>
</dd>
</div>
</dl>
</div>
</div>
</div>
</div>
Output
Takeaways:
As you are using HTML Tag helper class that is #await Html.PartialAsync("_DetailTeamPartialView", item) so you don't need to use below Detail action on your controller. Index action would handled the _DetailTeamPartialView autometically.
public IActionResult Detail(int id)
{
Team team = _dbcontext.Team
.Include(a => a.TeamMembers)
.Where(e => e.TeamId == id).FirstOrDefault();
return PartialView("_DetailTeamPartialView", team);
}

model item passed into the dictionary is of type PagedList.PagedList[] but this dictionary requires a model item of type

Im trying to use view models in my project but I have this error:
The model item passed into the dictionary is of type
'PagedList.PagedList1[ContosoUniversity.Models.Course]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[ContosoUniversity.ViewModels.CourseViewModel]'.
Controller:
public ActionResult Index(int? page)
{
int pageNumber = page ?? 1;
var courses = courseService.GetAll();
var coursesViewList = Mapper.Map<IEnumerable<Course>, IEnumerable<CourseViewModel>>(courses);
var model = coursesViewList.ToPagedList(pageNumber, PageSize);
return View(model);
}
View:
#model IEnumerable<ContosoUniversity.ViewModels.CourseViewModel>
#using PagedList.Mvc;
#using PagedList;
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Credits)
</th>
<th>
Students
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Credits)
</td>
<td>
#string.Join(",", item.Enrollments.Select(e => e.Student.FullName))
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.CourseID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.CourseID })
</td>
</tr>
}
</table>
#Html.PagedListPager((IPagedList)Model, page => Url.Action("Index", new { page }))
Could somebody help me to resolve a problem please?
You are passing Model of type PagedList.PagedList1<ContosoUniversity.Models.Course> while your View is strongly typed with IEnumerable<ContosoUniversity.ViewModels.CourseViewModel>.
You need to pass IEnumerable<T> from action or set Model of View to PagedList<T> or you can overcome this issue by wrapping it inside a ViewModel in following way:
public class CoursesVM
{
public PagedList.IPagedList<CourseViewModel> Courses { get; set; }
}
In action:
public ActionResult Index(int? page)
{
int pageNumber = page ?? 1;
var courses = courseService.GetAll();
var coursesViewList = Mapper.Map<IEnumerable<Course>, IEnumerable<CourseViewModel>>(courses);
var model = new CoursesVM();
model.Courses = coursesViewList.ToPagedList(pageNumber, PageSize);
return View(model);
}
and in View:
#model ContosoUniversity.ViewModels.CoursesVM
#using PagedList.Mvc;
#using PagedList;
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Credits)
</th>
<th>
Students
</th>
<th></th>
</tr>
#foreach (var item in Model.Courses) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Credits)
</td>
<td>
#string.Join(",", item.Enrollments.Select(e => e.Student.FullName))
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.CourseID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.CourseID })
</td>
</tr>
}
</table>

Cannot Access ViewModel Class member inside razor view

I cannot access a member of my class inside the view. All other members are accessible.
The following member "ListOfCategories" is not available in intellisense or at run time inside the view.
Error: There is no ViewData item of type 'IEnumerable' that has the key 'ListOfCategories'
My ViewModelClass
public class ArticleEditViewModel
{
public int ID { get; set; }
[Required]
public string Title { get; set; }
public List<Category> ListOfCategories = new List<Category>();
}
My Razor View
#model rrrr.ViewModels.Article.ArticleEditViewModel
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_LayoutSecure.cshtml";
}
<div>
#Html.ActionLink("Back to Articles", "Index")
</div>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.ID)
<div class="tableHeader">
<h2>Update Article</h2>
</div>
<table id="RegistrationForm">
<tbody>
<tr>
<td>Title</td>
<td>
#Html.TextBoxFor(model => model.Title, new { #class = "registerinput" })
</td>
<td class="leftWarning">
#Html.ValidationMessageFor(model => model.Title)
</td>
</tr>
<tr>
<td>Category</td>
<td>
#Html.DropDownList(model => model.ListOfCategories, Model.CategoryID)
</td>
<td class="leftWarning">
#Html.ValidationMessageFor(model => model.CategoryID)
</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Update Article" class = "css_button_4" />
</td>
</tr>
</tbody>
</table>
}
Use DropdownListFor instead. The code will be something like this:
#Html.DropDownListFor(model => model.CategoryId, Model.ListOfCategories.Select(c => new SelectListItem { Text = c.CategoryName, Value = c.CategoryId }))

Accordion within table rows

I am using Twitter Bootstrap. Currently I am working on Master Details looks alike table, which I am planning to place an accordion into each table's row and if it is expanded, the partial view will be reload and displayed.
Somehow it does not work as expected but if I change it to Modal, the partial view loaded perfectly.
This is the controller that process and returning the values:
public ActionResult Index(int id,int? page)
{
List<CustomerProduct> customerProducts =
(from c in RepositoryProduct.Reload(id)
select c).ToList<CustomerProduct>();
return PartialView("_CustomerProducts", customerProducts);
}
and this is the table in the view :
<table id="tbl" class="table table-condensed" style="border-collapse:collapse;">
<thead>
<tr>
<th>
#Html.ActionLink("Customer Name", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.First().CustLocalName)
</th>
<th>
#Html.ActionLink("Country", "Index", new { sortOrder = ViewBag.CountrySortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.First().City)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr data-toggle="collapse">
<td style="display:none;">
#Html.DisplayFor(modelItem => item.CustID)
</td>
<td>
#Html.DisplayFor(modelItem => item.CustName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CustLocalName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Country.CountryName)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
<a class="btn btn-small btn-info" type="button" href="#Url.Action("Index", "CustomerProduct", new { id = item.CustID })" data-toggle="collapse" data-target="##item.CustID" >Products</a>
</td>
</tr>
<tr>
<td colspan="6" class="hiddenRow">
<div id="#item.CustID" class="accordian-body collapse" tabindex="-1">
<div class="accordion-header">
<label>
<strong>#item.CustName product(s)</strong>
</label>
</div>
<div class="accordion-body">TEST</div>
</div>
</td>
</tr>
}
</tbody>
</table>
this is part of the code that calling the controller Index function :
<a class="btn btn-small btn-info" type="button" href="#Url.Action("Index", "CustomerProduct", new { id = item.CustID })" data-toggle="collapse" data-target="##item.CustID" >Products</a>
Actually I would like to load the partialview(_CustomerProduct) in the div class="accordion-body" as what I did in div class="modal-body" but no success. May I know if it is possible to do it and if yes, may I know how?
Any help will be appreciated.
for me to get the view to work i used
<td colspan="6" class="hiddenRow">
<div id="#item.CustID" class="accordian-body collapse" tabindex="-1">
<div class="accordion-header">
<label>
<strong>#item.CustName product(s)</strong>
</label>
</div>
<div class="accordion-body">
#Html.Partial("_CustomerProduct")
</div>
</div>
</td>

Edit IEnumerable null on controller

I cant use one List<album> on this, only on view whitout edit tags, I have one view working good, but I can't edit one list of them.
#model IEnumerable<MyMixtapezServerCodeHomePage.Models.album>
#using (Html.BeginForm("FeatureSystem", "album", FormMethod.Post))
{
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.name)
</th>
<th>
#Html.DisplayNameFor(model => model.feature)
</th>
<th>
#Html.DisplayNameFor(model => model.feature_order)
</th>
<th></th>
</tr>
#foreach (var item in #Model)
{
<tr>
<td>
<div class="editor-label">
#Html.LabelFor(model => item.name)
</div>
<div class="editor-field">
#Html.EditorFor(model => item.name,"album")
#Html.ValidationMessageFor(model => item.name)
</div>
</td>
<td>
<div class="editor-label">
#Html.LabelFor(model => item.feature,"album")
</div>
<div class="editor-field">
#Html.EditorFor(model => item.feature)
#Html.ValidationMessageFor(model => item.feature)
</div>
</td>
<td>
<div class="editor-label">
#Html.LabelFor(model => item.feature_order)
</div>
<div class="editor-field">
#Html.EditorFor(model => item.feature_order,"album")
#Html.ValidationMessageFor(model => item.feature_order)
</div>
</td>
<td></td>
</tr>
}
<input type="submit" />
</table>}
CONTROLLER
[HttpPost]
public ActionResult FeatureSystem(IEnumerable<album> albums)
{
foreach (album album in albums)
{
if (ModelState.IsValid)
{
albumRepository.Update(album);
albumRepository.SaveChanges();
}
}
return RedirectToAction("Index");
}
I recieve albums is null, why? Can I edit one list? I only need this.
Use a IList instead of IEnumerable in the view and replace the foreach loop with a for loop.
Step 1:
Use
#model IList <MyMixtapezServerCodeHomePage.Models.album>
instead of
#model IEnumerable<MyMixtapezServerCodeHomePage.Models.album>
Step 2:
Use
#for (var i = 0; i < Model.Count; i++)
instead of
#foreach (var item in #Model)
Refer How to pass IEnumerable list to controller in MVC including checkbox state? for more details.
I believe this has not changed since mvc3
So to have an editable collection you've got to use a for loop, not a foreach, or binding won't work.
#for(var i = 0; i < Model.Count; i++)
{
<tr>
<td>
<div class="editor-label">
#Html.LabelFor(model => Model[i].name)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model[i].name,"album")
#Html.ValidationMessageFor(model => Model[i].name)
</div>
</td>
<td>
...
}
take a look at this, old, but I think not outdated.