Changing number of table elements displayed on page resets my search results - asp.net

I have numerous data displayed in a table, let's say a long list of users (first name & last name), so I set up a paging feature to display the elements by pages via the PagedList NuGet package. I was inspired by this tutorial: https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
I implemented a drop-down list in my view, so that I can directly choose the number of elements to display per page. I managed to include a jQuery script that makes the page size update whenever the drop-down list has a new selected value.
Using the mentioned tutorial , I also added a search feature: submitting a string in a search form allows to filter the data.
My problem is: changing the page size by selecting a new value in the drop-down list after having done a search doesn't work: the search results are reset, all the entries being displayed instead. I guess I forgot to pass some parameter somewhere but I just can't figure out where...
Here is my controller:
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page, int? PageSize)
// Sort order is passed to view in order to keep it intact while clicking in another page link
ViewBag.CurrentSort = sortOrder;
// Ascending or descending sorting by first or last name according to sortOrder value
ViewBag.LastNameSortParm = String.IsNullOrEmpty(sortOrder) ? "lastname_desc" : "";
ViewBag.FirstNameSortParm = sortOrder == "firstname" ? "firstname_desc" : "firstname";
// Not sure here
if (searchString == null)
{
searchString = currentFilter;
}
// Pass filtering string to view in order to maintain filtering when paging
ViewBag.CurrentFilter = searchString;
var users = from u in _db.USER select u;
// FILTERING
if (!String.IsNullOrEmpty(searchString))
{
users = users.Where(u => u.lastname.Contains(searchString)
|| u.firstname.Contains(searchString)
}
// Ascending or descending filtering by first/last name
switch (sortOrder)
{
case "lastname": // Ascending last name
users = users.OrderBy(u => u.lastname);
break;
case "lastname_desc": // Descending last name
users = users.OrderByDescending(u => u.lastname);
break;
case "firstname": // Ascending first name
users = users.OrderBy(u => u.firstname);
break;
case "firstname_desc": // Descending first name
users = users.OrderByDescending(u => u.firstname);
break;
default:
users = users.OrderBy(u => u.lastname);
break;
}
// DROPDOWNLIST FOR UPDATING PAGE SIZE
int count = _db.USER.OrderBy(e => e.Id).Count(); // Total number of elements
// Populate DropDownList
ViewBag.PageSize = new List<SelectListItem>() {
new SelectListItem { Text = "10", Value = "10", Selected = true },
new SelectListItem { Text = "25", Value = "25" },
new SelectListItem { Text = "50", Value = "50" },
new SelectListItem { Text = "100", Value = "100" },
new SelectListItem { Text = "All", Value = count.ToString() }
};
int pageNumber = (page ?? 1);
int pageSize = (PageSize ?? 10);
ViewBag.psize = pageSize;
return View(users.ToPagedList(pageNumber, pageSize));
}
And my Index.cshtml view:
<script src="~/Scripts/jquery-3.2.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () { // Submit pageSizeForm when another pageSize value is selected
$("#pageSize").change(function () {
$("#pageSizeForm").submit();
});
});
</script>
#model PagedList.IPagedList<AfpaSIPAdmin.Models.USER>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Users management";
}
<h1>Users management</h1>
<!-- Creating a new entry in table -->
<p>
#Html.ActionLink("Create new user", "Create")
</p>
<!-- Filtering table entries -->
#using (Html.BeginForm("Index", "Users", FormMethod.Get, new { id = "filterForm" }))
{
<p>
Filter: #Html.TextBox("SearchString", ViewBag.CurrentFilter as string, new { #placeholder = "First or last name..." })
<input type="submit" value="Apply"/>
</p>
}
<!-- Display table -->
<table class="table">
<tr>
<th>
#Html.ActionLink("Last name", "Index", new {
sortOrder = ViewBag.LastNameSortParm,
currentFilter = ViewBag.CurrentFilter
})
</th>
<th>
#Html.ActionLink("First name", "Index", new {
sortOrder = ViewBag.FirstNameSortParm,
currentFilter = ViewBag.CurrentFilter
})
</th>
<th style="min-width: 170px"></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td style = "min-width: 150px">
#Html.DisplayFor(modelItem => item.lastname)
</td>
<td style = "min-width: 150px">
#Html.DisplayFor(modelItem => item.firstname)
</td>
<td> <!-- Using images as buttons for actions -->
<a href="#Url.Action("Edit", "Users", new { id = item.Id })" title="Edit">
<img src="~/Content/images/edit.gif" />
</a>
<a href="#Url.Action("Details", "Users", new { id = item.Id })" title="Details">
<img src="~/Content/images/info.gif" />
</a>
<a href="#Url.Action("Delete", "Users", new { id = item.Id })" title="Delete">
<img src="~/Content/images/delete.gif" />
</a>
</td>
</tr>
}
</table>
<br/>
<!-- Paging -->
#using (Html.BeginForm("Index", "Users", FormMethod.Get, new { id = "pageSizeForm" }))
{
<div class="pager">
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) sur #Model.PageCount<br/>
#Model.Count of #Model.TotalItemCount elements
#Html.PagedListPager(Model, page => Url.Action("Index", new {
page,
sortOrder = ViewBag.CurrentSort,
currentFilter = ViewBag.CurrentFilter,
searchString = ViewBag.CurrentFilter,
pageSize = ViewBag.psize
}))
<!-- DropDownList for setting page size -->
Elements per page :
#Html.DropDownList("pageSize")
</div>
}

The reason is because you have 2 forms. When you submit the first form containing the textbox, the only value you send back to the controller is SearchString and all the other parameters in your method will be their default (for example when you return the view, PageSize will default to null and therefore return only 10 records even if the user previously selected say 50.
Likewise, when you submit the 2nd form containing dropdownlist for the page size, the value of SearchString will be null because its not sent in the request.
You need to have one form only containing both form controls. And if you wanted to send additional properties, for example the current sort order, then you can add those as query string values in the form element (for example, #using(Html.BeginForm("Index", "Users", new { sortOrder = .... }, FormMethod.Get))
I would also strongly recommend you use a view model containing the properties you need in the view and strongly bind to them rather than using ViewBag
public class UsersVM
{
public string SearchString { get; set; }
public int PageSize { get; set; }
public IEnumerable<SelectListItem> PageSizeOptions { get; set; }
.....
public IPagedList<USER> Users { get; set; }
}
View
#model UsersVM
...
#using(Html.BeginForm("Index", "Users", FormMethod.Get))
{
#Html.LabelFor(m => m.SearchString)
#Html.TextBoxFor(m => m.SearchString)
#Html.LabelFor(m => m.PageSize)
#Html.DropDownListFor(m => m.PageSize, Model.PageSizeOptions)
<input type="submit" value="Filter" />
}
....
<div class="pager">
Page #(Model.Users.PageCount < Model.Users.PageNumber ? 0 : Model.Users.PageNumber)
....
#Html.PagedListPager(Model.Users, page => Url.Action("Index", new {
page,
sortOrder = Model.CurrentSort,
currentFilter = Model.CurrentFilter,
searchString = Model.CurrentFilter,
pageSize = Model.PageSize
}))
</div>
and in the controller method, initialize a new instance of UsersVM and assign its properties
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page, int? pageSize)
{
UsersVM model = new UsersVM();
....
var users = from u in _db.USER select u;
....
pageSize = pageSize ?? 10;
model.PageSize = pageSize.Value;
model.Users = users.ToPagedList(pageNumber, pageSize);
model.PageSizeOptions = new List<SelectListItem> { .... };
return View(model);
}

Related

Return to Index page from detail with filters (EnumDropDownListFor) set MVC ASP.NET

I am having an issue trying to return to my index (List) page with my filter set correctly. The filter is never set on return from the details page and always defaults to the first value in the drop down list. Using the Html helper EnumDropDownListFor.
EDIT: I should point out that if I change the current month filter from the index page that it posts correctly to the Index ActionResult and the filter is correctly set back in the Index page. So the issue is when posting from the details page back to the Index page only.
Here's my code.
Model Code:
using System;
using System.Collections.Generic;
namespace ShiftPatternConfigurator.Models
{
// shift view
public class ShiftViewModel
{
public IEnumerable<Shift> Shifts { get; set; }
public Month Month { get; set; }
}
// shift model
public class Shift
{
public int ShiftNo;
public string ShiftName;
public DateTime StartTime;
public DateTime FinishTime;
public string Team;
public int Week;
public int CycleWeek = 0;
public string StartDay;
public DateTime StartDate;
}
// month enum
public enum Month
{
January = 1,
February = 2,
March = 3,
April = 4,
May = 5,
June = 6,
July = 7,
August = 8,
September = 9,
October = 10,
November = 11,
December = 12
}
}
Controller Code:
using ShiftPatternConfigurator.DataAccess;
using ShiftPatternConfigurator.Models;
using System;
using System.Web.Mvc;
namespace ShiftPatternConfigurator.Controllers
{
public class HomeController : Controller
{
// GET: Index
public ActionResult Index()
{
ViewBag.Title = "Shift Pattern";
ShiftViewModel monthShiftView = new ShiftViewModel
{
Month = new Month()
};
monthShiftView.Month = (Month)DateTime.Now.Month;
monthShiftView.Shifts = DbContext.GetShiftsByMonth(monthShiftView.Month);
return View(monthShiftView);
}
// POST: Index
[HttpPost]
public ActionResult Index(Month month)
{
ViewBag.Title = "Shift Pattern";
ShiftViewModel monthShiftView = new ShiftViewModel
{
Month = new Month()
};
monthShiftView.Month = month;
monthShiftView.Shifts = DbContext.GetShiftsByMonth(monthShiftView.Month);
return View(monthShiftView);
}
// GET: Details
public ActionResult Details(int shiftNo, Month monthFilter)
{
ViewBag.Title = "Shift Details";
ViewBag.MonthFilter = monthFilter;
Shift shift = DbContext.GetShiftByShiftNo(shiftNo);
return View(shift);
}
}
}
Index (List) Code:
#model ShiftPatternConfigurator.Models.ShiftViewModel
<div class="jumbotron">
<h1>#ViewBag.Title - #Model.Month</h1>
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.EnumDropDownListFor(x => x.Month)
<input type="submit" value="Select Month" class="btn btn-primary btn-sm" />
}
</div>
<table class="table">
<tr>
<th>Shift No</th>
<th>Shift Name</th>
<th>Start Time</th>
<th>Finish Time</th>
<th>Team</th>
<th>Week</th>
<th>Start Day</th>
<th>Start Date</th>
<th></th>
</tr>
#if (Model.Shifts.Count() > 0)
{
foreach (var item in Model.Shifts)
{
<tr>
<td>#item.ShiftNo</td>
<td>#item.ShiftName</td>
<td>#item.StartTime</td>
<td>#item.FinishTime</td>
<td>#item.Team</td>
<td>#item.Week</td>
<td>#item.StartDay</td>
<td>#item.StartDate.ToShortDateString()</td>
<td>
<div class="btn-group btn-group-xs">
#Html.ActionLink("Edit", "Edit", new { shiftNo = item.ShiftNo, monthFilter = Model.Month }, new { #class = "btn btn-primary" })
#Html.ActionLink("Details", "Details", new { shiftNo = item.ShiftNo, monthFilter = Model.Month }, new { #class = "btn btn-primary" })
</div>
</td>
</tr>
}
}
else
{
<tr>
<td colspan="10" align="center"><h2>No Data</h2></td>
</tr>
}
</table>
Detail Code:
#using ShiftPatternConfigurator.Models
#model Shift
<h2>#ViewBag.Title</h2>
<div>
<h4>Shift - #Model.ShiftNo</h4>
<hr />
<dl class="dl-horizontal">
<dt>Shift No:</dt>
<dd>#Model.ShiftNo</dd>
<dt>Shift Name</dt>
<dd>#Model.ShiftName</dd>
<dt>Start Time</dt>
<dd>#Model.StartTime.ToShortDateString() #Model.StartTime.ToLongTimeString()</dd>
<dt>Finish Time</dt>
<dd>#Model.FinishTime.ToShortDateString() #Model.FinishTime.ToLongTimeString()</dd>
<dt>Team:</dt>
<dd>#Model.Team</dd>
<dt>Week:</dt>
<dd>#Model.Week</dd>
<dt>Cycle Week:</dt>
<dd>#Model.CycleWeek</dd>
<dt>Start Day:</dt>
<dd>#Model.StartDay</dd>
<dt>Start Date:</dt>
<dd>#Model.StartDate</dd>
</dl>
</div>
<p>
#Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
#Html.ActionLink("Back to List-ActionLink", "Index", "Home", new { month = ViewBag.MonthFilter })
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.Hidden("month", (Month)ViewBag.MonthFilter)
<input type="submit" value="Back to List-Form" class="btn btn-primary btn-sm" />
}
#Ajax.ActionLink("Back to List-Ajax", "Index", "Home",
new { month = (Month)ViewBag.MonthFilter },
new AjaxOptions { HttpMethod = "POST" },
new { #class = "btn btn-primary btn-sm" })
</p>
I have tried the following ways to get back to my index page with the filter set:
#Html.ActionLink method
I have found that this will not work as ActionLink always sends a GET request so I cannot use this method.
#Html.ActionLink("Back to List-ActionLink", "Index", "Home", new { month = ViewBag.MonthFilter })
#Ajax.ActionLink method
Using the Ajax method the Index POST method gets hit but the page stays on the detail page.
#Ajax.ActionLink("Back to List-Ajax", "Index", "Home",
new { month = (Month)ViewBag.MonthFilter },
//new AjaxOptions { HttpMethod = "POST", OnSuccess = "window.location.href = '/'" },
new AjaxOptions { HttpMethod = "POST" },
new { #class = "btn btn-primary btn-sm" })
#Html.BeginForm method
With this method it posts correctly to the POST ActionResult correctly, however the drop down list defaults to the first in the list. So the filter is not passed correctly to the enumdropdownlistfor.
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.Hidden("month", (Month)ViewBag.MonthFilter)
<input type="submit" value="Back to List-Form" class="btn btn-primary btn-sm" />
}
Here is method 3 using #Html.BeginForm to post back, in screenshots with debugging values shown:
Page is launched and hits the GET index ActionResult, the Models Month enum is set to the current month and the list of shifts are returned from the BDcontext and assigned to the Model.
The Index view then renders the Html setting the EnumDropDownListFor to the currect date correctly
As you can see from the image the month is set to the current month.
EDIT: Here is the correctly generated HTML output by the #Html.EnumDropDownListFor helper
After Selecting the details link, the code hits the GET details ActionResult and renders the view correctly.
After hitting the back to List-Form button the POST Index Action Result is hit correctly setting all the parameters.
But the view is rendered with the Month filter defaulting to the first in the list, not my selected month.
EDIT: Here is the incorrectly generated HTML output by the #Html.EnumDropDownListFor helper
Please help with suggestions how I can make this work.
So I found a work around for my issue, although it feels like it is a hack opposed to the correct way to do it. Maybe someone can comment as to why it didn't work the way I wanted it to?
What I did was the following:
Use ActionLink in my Detail page passing a parameter.
Handle the optional parameter in my GET Index ActionResult method.
So the code looks like this.
Detail View Action Link:
#Html.ActionLink("Back to List", "Index", "Home", new { monthFilter = ViewBag.MonthFilter }, new { #class = "btn btn-primary btn-sm" })
Index (List) GET ActionResult:
// GET: Index
public ActionResult Index(string monthFilter)
{
ViewBag.Title = "Shift Pattern";
ShiftViewModel monthShiftView = new ShiftViewModel
{
Month = new Month()
};
// hack to fix issue with filter not being passed back to index page from Details view
if(monthFilter == null)
monthShiftView.Month = (Month)DateTime.Now.Month;
else
monthShiftView.Month = (Month)Enum.Parse(typeof(Month), monthFilter); ;
monthShiftView.Shifts = DbContext.GetShiftsByMonth(monthShiftView.Month);
return View(monthShiftView);
}
So as you can see I handle the month value, by using the current month if the month value passed in is null or I use the value passed in if its available to be used.

Click on thumbnail and route to Controller method

I written a view that display a table listing of thumbnails. It is working now. Next I am writing another view, which display a new view with detailed information of the
item thumbnail which was clicked. Right now, I am not sure how to add the information which makes the thumbmail clickable that routes to the GetDetailInfo Controller method
that return a detailed information view.
Here is my thumbnail table list code:
<table class="table-responsive" width="100%">
<tbody>
#foreach (var productGroup in Model.Select((e, i) => new { Product = e, Grouping = (i / 4) }).GroupBy(e => e.Grouping))
{
<tr>
#foreach (var product in productGroup)
{
<td>
<div><br /></div>
<img src=#product.Product.Thumbnail style="width: 100px; height: 100px" />
<div><br /></div>
</td>
}
</tr>
}
</tbody>
</table>
Here is my the Controller method which I am writing which is called when the thumbnail is click and return a detailed view.
[MvcSiteMapNode(Title = "Item Detail", ParentKey = "Item-Home", Key = "Item-Detail", PreservedRouteParameters = "itemId")]
[Route("~/item/{itemId}/detail")]
public async Task<ActionResult> GetDetailInfo(int itemId)
{
var result = await ItemService.GetDetailInfo(contentId) );
return View(result.Dto);
}
I am not sure how to route the click on thumnbnail to this controller method to return a new detail info view. Any help is appreciated. Thanks
There are two common ways to make an image as a link.
1 - Using a link tag.
<a href="#Url.Action("GetDetailInfo", "Controller", new { itemId = product.Product.Id })">
<img src="#product.Product.Thumbnail" style="width: 100px; height: 100px" />
</a>
2 - Using a custom Html Helper
Source:
public MvcHtmlString ActionImage(this HtmlHelper htmlHelper,
string controller,
string action,
object routeValues,
string imagePath,
string alternateText = "",
object htmlAttributes = null)
{
var anchorBuilder = new TagBuilder("a");
var url = new UrlHelper(HtmlHelper.ViewContext.RequestContext);
anchorBuilder.MergeAttribute("href",url.Action(action,controller,routeValues));
var imgBuilder = new TagBuilder("img");
imgBuilder.MergeAttribute("src", url.Content(imagePath));
imgBuilder.MergeAttribute("alt", alternateText);
var attributes = (IDictionary<string, object>) HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
imgBuilder.MergeAttributes(attributes);
string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);
anchorBuilder.InnerHtml = imgHtml;
return MvcHtmlString.Create(anchorBuilder.ToString());
}
Using:
#Html.ActionImage("Controller", "GetDetailInfo", new { itemId = #product.Product.Id }, "#product.Product.Thumbnail", "alternateText")
Asp.Net MVC Html Helper to create link with an image
The first method is handy - and rightly commented by Bardicer in your question, - but the second one is more practical.

How to pass model from one partial view to another partial view

I have a model called Result. Suppose this has 4 fields, like student_id, marks, status, remarks.
Now I have a view in which student listing is shown. In front of each student, there is a button for enter marks of exam. On clicking on button a pop-up will open and there will be 2 fields student_id, marks and 2 buttons 'pass' and 'fail'.
On clicking on fail button another pop-up will appear for enter remarks only.
Now my question is that, how can I retain values of first pop-up on second pop-up, As on clicking on 'submit' button of second pop-up, I will save all the details.
I know a way to do this using hidden fields in second pop-up. Is there any other way to do this?
Model classes are:
1. User (id, name, f_name, address...)
2. Result (student_id, marks, grade, remarks)
Student List view
#{
List<User> Student = (List<User>)ViewData["Student"];
}
<table id="table_id">
<tr>
<th class="dbtc">S.No.</th>
<th class="dbtc">Student Name)</th>
<th style="width: 110px">Operate</th>
</tr>
#foreach (User usr in Student)
{
int index = Student.IndexOf(usr);
<tr>
<td class="dbtc">
#(Student.ToList().IndexOf(usr) + 1)
</td>
<td>
#Html.ActionLink(usr.FirstName + " " + usr.LastName, "Details", "User", new { id = usr.Id }, null)
</td>
<td>
#Ajax.ActionLink("Examine", "Result", new { id = Model.Id, userId = usr.Id }, new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "divPopup",
InsertionMode = InsertionMode.Replace,
OnSuccess = "openPopup('Examine Content')"
})
</td>
</tr>
First Partial view of examine
#model ComiValve.Models.Result
#using (Html.BeginForm("ExamPass", "Student", new { #id = (int)ViewBag.id, userId = (int)ViewData["UserId"] }, FormMethod.Post))
{
<div id="divExamAdvice"></div>
<div class="editor-label">
#Html.DisplayNameFor(model => model.Name)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Marks)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Grade)
</div>
<div class="login_submit_div">
<input type="submit" value="Pass" />
#Ajax.ActionLink("Fail", "ExamAdvice", new { id = (int)ViewBag.id, userId = (int)ViewData["UserId"] }, new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "divPopup",
OnSuccess = "openPopup('Exam Advice')"
})
</div>
}
Second partial view for remaks (when user click on fail, then this view will open.)
#model ComiValve.Models.ExamContent
#using (Html.BeginForm("ExamFail", "Student", new { id = Model.id }, FormMethod.Post))
{
<div id="divExamAdvice"></div>
<div class="editor-label">
#Html.DisplayNameFor(model => model.Remarks)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Remarks)
</div>
<div class="left">
<input type="submit" value="Confirm Fail" />
</div>
}
Methods of Controller
public virtual ActionResult ExamContent(int id, int userId)
{
ViewBag.IsApprove = true;
ViewBag.UserId = userId;
ViewBag.id = id;
return PartialView("ExamContent");
}
public virtual ActionResult ExamAdvice(int id, int userId)
{
ViewBag.IsApprove = true;
if (Request.IsAjaxRequest())
{
Result result = new Result();
result.id = id;
result.User = db.Users.Find(userId);
return PartialView("ExamAdvice", result);
}
else
{
return RedirectToAction("Index");
}
}
Why are you passing the model between partial views. You can create a single Model and use it on both the views. In case of having two different tables, create the two different "Lists" of "Table" type. Like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Web.Mvc;
namespace LearningMVCapp.Models
{
public class Data
{
public List<tbl_Dept> lstDepatrment;
public List<tbl_employees> lstEmployees;
//other properties
}
}
You can also use session instead of hidden fields, refer this link http://www.dotnet-tricks.com/Tutorial/mvc/906b060113-Controlling-Session-Behavior-in-Asp.Net-MVC4.html.

ASP.NET MVC4 + Get drop down value after HttpPost submit

So I want to get a value of the dropdown (== id of the account) to insert a new transaction
Here below you can find my View:
<div id="content">
<h2>Overschrijving</h2>
<p id="topmsg">velden met een * zijn verplicht</p><p> </p>
<dl class="clearfix form">
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl })) {
#Html.ValidationSummary(true, "Gelieve alles correct in te vullen.")
<dt>#Html.Label("Rekening: *")</dt>
<dd>#Html.DropDownList("ddlAccounts")</dd>
<dt>#Html.Label("Begunstigde: *")</dt>
<dd>#Html.TextBox("ToAccountNumber")</dd>
<dt>#Html.Label("Bedrag: *")</dt>
<dd>#Html.TextBox("Amount", null, new { #class = "inpshort" })</dd>
<dt>#Html.Label("Mededeling: ")</dt>
<dd>#Html.TextBox("Message", null, new { #class = "inplong" })</dd>
<dd class="buttons">
<input type="submit" value="Bevestigen" />
<input type="submit" value="Annuleren" />
</dd>
}
</dl>
</div>
this is the Controller code:
public ActionResult Transfer(int? id) {
Holder h = Holder.GetHolderByHolderId(Convert.ToInt32(User.Identity.Name));
List<Account> holderAccounts = Account.GetAccountsByHolderId(h.Id);
List<SelectListItem> ddlHolderAccounts = new List<SelectListItem>();
ddlHolderAccounts.Add(new SelectListItem { Text = "selecteer...", Value = "-1", Selected = true });
foreach (Account acc in holderAccounts) {
if (acc.Id == id) {
ddlHolderAccounts.Add(new SelectListItem { Text = acc.Name, Value = acc.Id.ToString(), Selected = true });
} else {
ddlHolderAccounts.Add(new SelectListItem { Text = acc.Name, Value = acc.Id.ToString() });
}
}
ViewData["ddlAccounts"] = ddlHolderAccounts;
return View();
}
[HttpPost]
public ActionResult Transfer(Transaction tra) {
if (ModelState.IsValid) {
Transaction.InsertTransaction(tra.Amount, tra.Message, tra.FromAccountId, tra.ToAccountNumber);
}
return View(tra);
}
Now I searched a lot with Google, it's probably better to use the DropDownListFor to fill your drop down list? But could anyone show me an example?
By looking at your code, I can see that you're not passing a list of SelectListItems to the DropDownList helper. You can do this one of two ways.
1- Bind it to a property on your model:
#Html.DropDownListFor(x=>Model.Property, new List<SelectListItem> { new SelectListItem { Text = "Item1", Value = "Value1" })
Or
2- You can do it without binding to a model property like:
#Html.DropDownList("propertyName", new List<SelectListItem> { new SelectListItem { Text = "Item1", Value = "Value1" } })
If you're using the second approach then your controller action must accept "propertyName" as a parameter when submitting.
And don't forget to provide a list of SelectListItems to select from (which you're not doing in your code).
Hope this helps.
should be
#Html.DropDownListFor(x=>Model.Property, new List { new SelectListItem { Text = "Item1", Value = "Value1" }})

Setting A Variable With #Html.TextBox MVC3 ASP.Net

I'm working on a MVC3 ASP.Net application. I'm trying to figure out how to set the Quantity variable so when I pass it through to the controller with Html.ActionLink it has the correct number. Here's the view's code
#model IEnumerable<GreatVideosTrainingApplication.Models.Candy>
#{
ViewBag.Title = "Great Videos";
List<GreatVideosTrainingApplication.Models.Candy> candies = new List<GreatVideosTrainingApplication.Models.Candy>();
foreach (var candy in Model)
{
candies.Add(candy);
}
var grid = new WebGrid(candies);
var Quantity = 0;
}
<p>Welcome To Great Videos! The best source for your favorite DVDs and Blu-Rays</p>
<img src ="/Content/Images/dvd50.jpg" />
<p></p>
<img src="/Content/Images/bluray.jpg" />
<form method="post" action="/ShoppingCart/AddToCandyCart/"+item.CandyID >
#grid.GetHtml(#columns: grid.Columns(
grid.Column("Name"),
grid.Column("Price"),
grid.Column("Quantity", format: (item) => #Html.TextBox("Quantity", #Quantity)),
grid.Column("AddToCart", format: (item) => Html.ActionLink("Add To Cart", "AddToCandyCart", "ShoppingCart", new { id = item.CandyID, quantity = #Quantity }, ""))
)
)
</form>
I'm trying to set the value for the quantity with the Html.TextBox but it's not working. Keep in mind here I don't know javascript, and I'm extremely new to MVC3. Any and all help is greatly appreciated though.
public ActionResult AddToCandyCart(int id, FormCollection values)
{
// Add it to the shopping cart
var quantity = values["Quantity"];
var cart = ShoppingCart.GetCart(this.HttpContext);
// Retrieve the video from the database
var addedCandy = storeDB.Candies.Single(Candy => Candy.CandyID == id);
cart.AddToCandyCart(addedCandy, int.Parse(quantity));
// Go back to the main store page for more shopping
return RedirectToAction("Index");
}
The following code worked for me when including a textbox. I had trouble with the html helpers so I just wrote the code for the input box directly. I hope this helps.
grid.Column("Quantity", format: #<text><input name="Quantity" type="text" value="#item.Quantity"</text>))
Figured out the problem from mixing a variety of sources. Wanted to thank everyone. Here's the view.
#model IEnumerable<GreatVideosTrainingApplication.Models.Candy>
#{
ViewBag.Title = "Great Videos";
List<GreatVideosTrainingApplication.Models.Candy> candies = new List<GreatVideosTrainingApplication.Models.Candy>();
foreach (var candy in Model)
{
candies.Add(candy);
}
var grid = new WebGrid(candies);
var Quantity = 0;
}
<p>Welcome To Great Videos! The best source for your favorite DVDs and Blu-Rays</p>
<img src ="/Content/Images/dvd50.jpg" />
<p></p>
<img src="/Content/Images/bluray.jpg" />
<form method="post" action="../ShoppingCart/AddToCandyCart/" >
#using (Html.BeginForm()) {
#grid.GetHtml(#columns: grid.Columns(
grid.Column("Name"),
grid.Column("Price"),
grid.Column("Quantity", format: #<text><input name="Quantity" type="text" value="#Quantity"</text>),
grid.Column("AddToCart", format: #<text><input type="submit" value="Add To Cart" name="submit" /></text>)
)
)
}
</form>
Here's the Action Controller
[HttpPost]
public ActionResult AddToCandyCart(FormCollection values)
{
int id = 1;
string[] quantities = values["Quantity"].Split(',');
foreach (var item in quantities)
{
try
{
int quantity = int.Parse(item);
if (quantity >= 1)
{
// Add the candy to the shopping cart
var addedCandy = storeDB.Candies.Single(Candy => Candy.CandyID == id);
var cart = ShoppingCart.GetCart(this.HttpContext);
cart.AddToCandyCart(addedCandy, int.Parse(item));
}
}
catch (Exception e)
{
return View("Failed");
}
id++;
}
// Go back to the main store page for more shopping
return RedirectToAction("Index");
}

Resources