#Html.HiddenFor returning null value - asp.net-mvc

I am trying to return the results of a table back to the controller for further manipulation. Once returned to the controller the value shows as null. In the past I have been able to use #Html.HiddenFor to return the values but it doesn't seem to be working in this instance. Not sure what I am doing wrong here. Any help is greatly appreciated.
#model IEnumerable<Project.Models.Item>
#{
ViewBag.Title = "Welcome to The Project";
}
#using (Html.BeginForm("UpdateQuality", "Home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<div class="row">
<div class="form-group">
<table class="table table-bordered">
<tr>
<th>#Html.DisplayNameFor(m => m.Name)</th>
<th>#Html.DisplayNameFor(m => m.SellIn)</th>
<th>#Html.DisplayNameFor(m => m.Quality)</th>
</tr>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>#Html.DisplayFor(m => m.ElementAt(i).Name)</td>
<td>#Html.DisplayFor(m => m.ElementAt(i).SellIn)</td>
<td>#Html.DisplayFor(m => m.ElementAt(i).Quality)</td>
#Html.HiddenFor(m => m.ElementAt(i).Name)
#Html.HiddenFor(m => m.ElementAt(i).SellIn)
#Html.HiddenFor(m => m.ElementAt(i).Quality)
</tr>
}
</table>
<div class="form-group">
<div style="margin-top: 50px">
<input type="submit" class="btn btn-primary" value="Advance Day"/>
</div>
</div>
</div>
</div>
}
And here is the controller which returns null.
public ActionResult UpdateQuality(List<Item> Items )
{
return View("Index", (object)Items);
}

You cannot use ElementAt() in a HtmlHelper method that generates form controls (look at the name attribute your generating - it does not match your model).
Either change the model to be IList<T>
#model List<Project.Models.Item>
and use a for loop
#for (int i = 0; i < Model.Count; i++)
{
....
#Html.HiddenFor(m => m.[i].Name)
....
or change use a custom EditorTemplate for typeof Item, and in the main view, use #Html.EditorFor(m => m) to generate the correct html for each item in the collection.

Related

ASP MVC 5 Post a form from a link

I need to make a custom data grid view with multi column filtering and pagination. so i made a view model winch will encapsulate three class
IEnumerable from the data.
Filter class with some properties
Pager to holder page size, current page, total pages etc ..
Filtering working fine but pagination not :(. as i loose the view model when pressing pagination link "It seems that i need to also submit the search form"
Any one can show how i can submit the form when pressing a link.
here is my view
#model TestFilteringAndPagination.ViewModels.CarViewModel
#{
ViewBag.Title = "Home Page";
}
#*Search form*#
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "frm" }))
{
#Html.HiddenFor(m => Model.Pager.CurrentPage)
#Html.HiddenFor(m => Model.Pager.PageSize)
#Html.HiddenFor(m => Model.Pager.EndPage)
#Html.HiddenFor(m => m.Pager.StartPage)
<div class="form-inline">
<div class="form-group">
<label>Car No</label>
#Html.EditorFor(x => x.Filter.CarNumber, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Line name</label>
#Html.EditorFor(x => x.Filter.LineName, new { #class = "form-control" })
</div>
<button type="submit" class="btn btn-default">Search</button>
</div>
<ul class="pagination">
#for (var page = Model.Pager.StartPage; page <= Model.Pager.EndPage; page++)
{
<li class="#(page == Model.Pager.CurrentPage ? "active" : "")">
#page
</li>
}
</ul>
}
#*Data grid*#
<table class="table">
<thead>
<tr>
<th>
Car number
</th>
<th>
Car Line
</th>
</tr>
</thead>
<tbody>
#foreach (var car in Model.Cars)
{
<tr>
<td>
#Html.DisplayFor(x => car.CarNumber)
</td>
<td>
#Html.DisplayFor(x => car.LineName)
</td>
</tr>
}
</tbody>
</table>
You can install the PagedList.MVC NuGet Package, see this post for more info about how to create exactly what you want.
Sorting, Filtering, and Paging with the Entity Framework in an ASP.NET MVC Application

Returning specific table data from the view to the controller? asp.net MVC

So I have a view which is currently displaying a table of data from the database with a select/selectall checkbox in place. What I'd like to do is be able to get a list of my CustomerNumbers and whether or not they have been checked and return it to my controller for further action.
Below is my how my view is currently written. I have tried numberous ways to get this to work and I am stumped.
#model MassInactiveInspections.Models.CustomerInfoList
<div class="container">
<h2>#ViewBag.Title</h2>
<div class="bs-callout bs-callout-info" style="margin-bottom: 0px;">
</div>
<div class="col-md-8">
#using (Html.BeginForm("SelectedCustomers", "Home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
<table class="table table-bordered">
<tr>
<th class="active">#Html.DisplayName("Select All?")<input type="checkbox" class="select-all checkbox" name="select-all" /></th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().BusinessName)</th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().CustomerName)</th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().CustomerNumber)</th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().InspectionCycleDescription)</th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().LastInspectionDate)</th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().RouteCode)</th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().RouteID)</th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().SiteNumber)</th>
<th>#Html.DisplayNameFor(m => m.CustomerInfoListView.FirstOrDefault().SystemCode)</th>
</tr>
#foreach (var item in Model.CustomerInfoListView)
{
<tr>
<td class="active"> <input id="Selected" input type="checkbox" class="select-item checkbox" name="select-item" value="1000" /> </td>
<td>#Html.DisplayFor(modelItem => item.BusinessName)</td>
<td>#Html.DisplayFor(modelItem => item.CustomerName)</td>
<td>
#Html.DisplayFor(modelItem => item.CustomerNumber)
#Html.HiddenFor(m => m.CustomerInfoListView.FirstOrDefault().CustomerNumber)
</td>
<td>#Html.DisplayFor(modelItem => item.InspectionCycleDescription)</td>
<td>#Html.DisplayFor(modelItem => item.LastInspectionDate)</td>
<td>#Html.DisplayFor(modelItem => item.RouteCode)</td>
<td>#Html.DisplayFor(modelItem => item.RouteID)</td>
<td>#Html.DisplayFor(modelItem => item.SiteNumber)</td>
<td>#Html.DisplayFor(modelItem => item.SystemCode)</td>
</tr>
}
</table>
</div>
<div class="form-group">
<div style="margin-top: 50px">
<input type="submit" id="btnLost" class="btn btn-primary" value="Lost"/>
<input type="submit" class="btn btn-primary" name="OOBButton" value="OOB" />
<input type="submit" class="btn btn-primary" name="RefusedButton" value="Refused" />
</div>
</div>
}
</div>
</div>
and finally my controller
[HttpPost]
public ActionResult SelectedCustomers(CustomerInfoList
customerNumberList)
{
return View("ViewCustomerInfo");
}
also here is my javascript for the checkboxes
[HttpPost]
public ActionResult SelectedCustomers(CustomerInfoList customerNumberList)
{
return View("ViewCustomerInfo");
}
//column checkbox select all or cancel
$("input.select-all").click(function () {
var checked = this.checked;
$("input.select-item").each(function (index, item) {
item.checked = checked;
});
});
//check selected items
$("input.select-item").click(function () {
var checked = this.checked;
console.log(checked);
checkSelected();
});
//check is all selected
function checkSelected() {
var all = $("input.select-all")[0];
var total = $("input.select-item").length;
var len = $("input.select-item:checked:checked").length;
console.log("total:" + total);
console.log("len:" + len);
all.checked = len === total;
}
});
Not sure if it is the best way to handle it but I simply added the fields that I wanted into a HiddenFor helper and they were returned to my the appropriate controller. Thanks everyone for the help.
#Html.HiddenFor(m => m.additionalCustomerInfoListView[i].CustomerNumber)

MVC4 Filtering with checkboxes

I have created create function in my controller which display all genres in checkoxes like this:
Controller:
public ActionResult Create()
{
var db = new MainDatabaseEntities();
var viewModel = new ANIME
{
GENRES = db.GENRES.Select(c => new { ID_GE = c.ID_GE, GENRE = c.GENRE, isSelected = false }).ToList().Select(g => new GENRES
{
ID_GE = g.ID_GE,
GENRE = g.GENRE,
isSelected = false
}).ToList()
};
return View(viewModel);
}
View:
#model AnimeWeb.Models.ANIME
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
<tr>
<td class="lefttablecontent" id="top">
<div class="editor-label">
#Html.HiddenFor(model => model.ID_AN)
</div>
<div class="editor-label">
Original title
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TITLE_OR)
#Html.ValidationMessageFor(model => model.TITLE_OR)
</div>
<div class="editor-label">
English title
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TITLE_EN)
#Html.ValidationMessageFor(model => model.TITLE_EN)
</div>
<div class="editor-label">
Genres
</div>
<div class="editor-list">
#Html.EditorFor(model => model.GENRES)
#Html.ValidationMessageFor(model => model.GENRES)
</div>
</td>
<td class="righttablecontent" id="top">
<p>
<input type="submit" value="Create" />
</p>
</td>
</tr>
</table>
}
}
EditorTemplate for Genres:
#model AnimeWeb.Models.GENRES
#Html.HiddenFor(model => model.ID_GE)
#Html.HiddenFor(model => model.GENRE)
<table>
<tr>
<td class=" right">
#Html.EditorFor(model => model.isSelected)
</td>
<td>
#Html.LabelFor(model => model.isSelected, Model.GENRE)
</td>
</tr>
</table>
Now I would like to display the same template with all genres and use it for filtering in index, but I'm not sure how to do this.
Controller:
public ActionResult Index(string sortOrder, string currentFilter, int? page)
{
using (var db = new MainDatabaseEntities())
{
ViewBag.CurrentSort = sortOrder;
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = searchString;
var anime = from s in db.ANIME.Include("GENRES")
select s;
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(anime.ToPagedList(pageNumber, pageSize));
}
}
View:
#model PagedList.IPagedList<AnimeWeb.Models.ANIME>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
}
<p>
#if (Roles.IsUserInRole("Administrator"))
{
#Html.ActionLink("Create New", "Create")
}
</p>
#foreach (var item in Model) //
{ //
#Html.EditorFor(modelItem => item.GENRES); // I'm not sure about this line
} //
<table>
<tr>
<th>
Anime
</th>
<th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.ActionLink(item.TITLE_OR, "Details", new { id = item.ID_AN })
</td>
</tr>
}
</table>
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
When I try to display it with #Html.EditorFor(modelItem => item.GENRES) it displays only genres that are selected within each anime but I need all genres to filter with them. I'm not even sure is this a good way to make it. Any suggestions?

How to update Partial View without full replacement

I have this partial view. This works, ie, when the user clicks the button, an ajax trip is made to the server, and it updates the partial view and it comes down and replaces the current div with the updated Div and shows the Promo Message.
However, it seems there should be a better way to do this. In other words, is it necessary to replace the entire partial view? Isn't there a way to send just the data up to the server, and then update just the message when it gets back, like maybe via a JSON call?
Controller:
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
orderViewModel.PromoMessage = "Promo has been applied";
return PartialView("PromoPartial", orderViewModel);
}
Partial View:
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "promo" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
#Html.DisplayFor(m=> m.PromoMessage)
</td>
</table>
</div>
}
you can do this to
Controller
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
//your processing code
return Content("Promo has been applied");
}
View
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { UpdateTargetId = "pcode" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
<div id="pcode"></div>
</td>
</table>
</div>
}
Instead of returning a PartialView you can always return a JSON object/array or some XML and use jQuery/JavaScript on your callback function to update the values of your input fields.
Here's an example of some code I use to return JSON from a Controller:
public ActionResult CurrentTags(int entityID)
{
Entity entity = db.Entity.Find(entityID);
var tags = from tag in entity.Tag
select new
{
id = tag.Name,
text = tag.Name
};
return this.Json(tags, JsonRequestBehavior.AllowGet);
}

MVC 4 binding nested list of lists result

I've done some research on this and seem to find posts that are either outdated or don't quite work in my situation. I may be using wrong keywords when searching though... =/
On my web page I have Tabs containing Group boxes that contain Lines which in turn contain Items.
So it is lists of lists 4 levels.
The problem:
When posting back, ViewModel.Tabs is null and I can't save anything.
Everything displays quite nicely, but nothing is posted back.
The code
Views/Shared/EditorTemplates/Tab.cshtml
#model AWMCCRM.Web.ViewModels.Tab
#Html.HiddenFor(vm => vm.Name)
<div id="tab-#Model.Name.Replace(" ", string.Empty)" class="tab-content two">
#Html.EditorFor(vm => vm.Groups)
</div>
Views/Shared/EditorTemplates/Group.cshtml
#model AWMCCRM.Web.ViewModels.Group
#Html.HiddenFor(vm => vm.Name)
<fieldset>
<legend>#Model.Name</legend>
#Html.EditorFor(vm => vm.Lines)
</fieldset>
Views/Shared/EditorTemplates/Line.cshtml
#model AWMCCRM.Web.ViewModels.Line
<div class="_100Max">
#Html.HiddenFor(vm => vm.Name)
#Html.EditorFor(vm => vm.Items)
</div>
Views/Shared/EditorTemplates/Item.cshtml
#model AWMCCRM.Web.ViewModels.Item
<div class="_#Model.DisplaySize" title="#Model.Description">
<p>
#Html.HiddenFor(x => x.DataType)
#Html.HiddenFor(x => x.Description)
#Html.HiddenFor(x => x.DisplaySize)
#Html.HiddenFor(x => x.DisplayType)
#Html.HiddenFor(x => x.IDsPiped)
#Html.HiddenFor(x => x.ItemType)
#Html.HiddenFor(x => x.Name)
#Html.LabelFor(vm => vm.Value, Model.Name)
#switch (Model.DisplayType.ToLower().Replace(" ", string.Empty))
{
case "checkbox":
#Html.CheckBoxFor(vm => Convert.ToBoolean(vm.Value))
break;
case "dropdownlist":
#Html.DropDownListFor(vm => vm.Value, Model.ValueOptionListItems)
break;
case "multiselectlist":
#Html.ListBoxFor(
x => x.SelectedValueList,
Model.ValueOptionListItems,
new { id = "itemValuesMultiSelect", multiple = "multiple", Size = 15 })
break;
case "radiobutton":
#Html.RadioButtonFor(vm => vm.Value, Model.Value)
break;
case "textarea":
#Html.TextAreaFor(vm => vm.Value)
break;
default:
#Html.TextBoxFor(vm => vm.Value)
break;
}
</p>
</div>
The ViewModel (cut down version)
namespace AWMCCRM.Web.ViewModels
{
public class PersonEditViewModel
{
public List<Tab> Tabs { get; set; }
//Other properties
//...
}
}
The View (cut down version)
#using (Html.BeginForm("Edit", "Person", FormMethod.Post, new { id = "validate-form", #class = "block-content form" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(x => x.PersonID)
#foreach (var tab in Model.Tabs)
{
#Html.EditorFor(vm => tab)
}
<input class="close-toolbox button" type="submit" value="Save">
}
Any suggestions?
Thanks
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
It's an old article, but it still applies.
I had this exact problem, but basically due to the model binding system you need to use an explicit for loop instead of a foreach loop, and reference your elements by their index.
#using (Html.BeginForm("Edit", "Person", FormMethod.Post, new { id = "validate-form", #class = "block-content form" }))
{
Html.AntiForgeryToken()
Html.HiddenFor(x => x.PersonID)
for (int i = 0; i<Model.Tabs.Count; i++)
{
Html.EditorFor(x => Model.Tabs[i])
}
<input class="close-toolbox button" type="submit" value="Save">
}

Resources