Paged list isn't working - asp.net

I did the Getting Started with ASP.NET MVC 3 (C#) tutorial by Rick Anderson, is a catalog of products, is already working, but, since i added a long list of products, now i need a pagedList to get just a number of products per page, looking around i found an example but isn't working, to my project i added on the Models file this class named IPagedList.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Presupuestos.Models
{
public interface IPagedList
{
int ItemCount
{
get;
set;
}
int PageCount
{
get;
set;
}
int PageIndex
{
get;
set;
}
int PageSize
{
get;
set;
}
bool IsPreviousPage
{
get;
}
bool IsNextPage
{
get;
}
}
public interface IPagedList<T> : IList<T>, IPagedList
{
}
public class PagedList<T> : List<T>, IPagedList<T>
{
private List<Productos> list;
private int p;
private int p_2;
public PagedList(IQueryable<T> source, int index, int pageSize)
{
this.ItemCount = source.Count();
this.PageSize = pageSize;
this.PageIndex = index;
this.AddRange(source.Skip(index * pageSize).Take(pageSize).ToList());
this.PageCount = (int)Math.Ceiling((double)this.ItemCount / this.PageSize);
}
public PagedList(List<T> source, int index, int pageSize)
{
this.ItemCount = source.Count();
this.PageSize = pageSize;
this.PageIndex = index;
this.AddRange(source.Skip(index * pageSize).Take(pageSize).ToList());
}
public PagedList(List<Productos> list, int p, int p_2)
{
// TODO: Complete member initialization
this.list = list;
this.p = p;
this.p_2 = p_2;
}
public int ItemCount
{
get;
set;
}
public int PageCount
{
get;
set;
}
public int PageIndex
{
get;
set;
}
public int PageSize
{
get;
set;
}
public bool IsPreviousPage
{
get
{
return (PageIndex > 0);
}
}
public bool IsNextPage
{
get
{
return (PageIndex + 1) * PageSize <= ItemCount;
}
}
}
public static class Pagination
{
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index, int pageSize)
{
return new PagedList<T>(source, index, pageSize);
}
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index)
{
return new PagedList<T>(source, index, 10);
}
}
}
Also, i added another class named HTMLHelpers.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;
using Presupuestos.Models;
namespace Presupuestos.Models
{
public static class ListPaging
{
public static MvcHtmlString Paging(this HtmlHelper html, IPagedList pagedList, string url, string pagePlaceHolder)
{
StringBuilder sb = new StringBuilder();
// only show paging if we have more items than the page size
if (pagedList.ItemCount > pagedList.PageSize)
{
sb.Append("<ul class=\"paging\">");
if (pagedList.IsPreviousPage && pagedList.PageIndex != 1)
{
// previous link
sb.Append("<li class=\"prev\"><a href=\"");
sb.Append(url.Replace(pagePlaceHolder, (pagedList.PageIndex - 1).ToString()));
sb.Append("\" title=\"Go to Previous Page\">prev</a></li>");
}
for (int i = 0; i < pagedList.PageCount; i++)
{
sb.Append("<li>");
if (i == pagedList.PageIndex)
{
sb.Append("<span>").Append((i + 1).ToString()).Append("</span>");
}
else
{
sb.Append("<a href=\"");
sb.Append(url.Replace(pagePlaceHolder, (i + 1).ToString()));
sb.Append("\" title=\"Go to Page ").Append((i + 1).ToString());
sb.Append("\">").Append((i + 1).ToString()).Append("</a>");
}
sb.Append("</li>");
}
if (pagedList.IsNextPage)
{
// next link
sb.Append("<li class=\"next\"><a href=\"");
sb.Append(url.Replace(pagePlaceHolder, (pagedList.PageIndex + 1).ToString()));
sb.Append("\" title=\"Go to Next Page\">next</a></li>");
}
sb.Append("</ul>");
}
return MvcHtmlString.Create(sb.ToString());
}
}
}
Finally this is the view file, i just added the #using presupuestos.models and the last html.paging at the end:
#model IEnumerable<Presupuestos.Models.Productos>
#using Presupuestos.Models
#{
ViewBag.Title = "Productos";
}
<h2>Catalogo de Productos</h2>
<p>
#Html.ActionLink("Agregar Producto", "Create")
</p>
<table>
<tr>
<th>
Marca
</th>
<th>
Codigo
</th>
<th>
Nombre
</th>
<th>
Envase
</th>
<th>
PresentaciĆ³n
</th>
<th>
Linea
</th>
<th>
Categoria
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.marca)
</td>
<td>
#Html.DisplayFor(modelItem => item.codigo)
</td>
<td>
#Html.DisplayFor(modelItem => item.nombre)
</td>
<td>
#Html.DisplayFor(modelItem => item.envase)
</td>
<td>
#Html.DisplayFor(modelItem => item.presentaciĆ³n)
</td>
<td>
#Html.DisplayFor(modelItem => item.linea)
</td>
<td>
#Html.DisplayFor(modelItem => item.categoria)
</td>
<td>
#Html.ActionLink("Editar", "Edit", new { id = item.ID }) |
#Html.ActionLink("Detalles", "Details", new { id = item.ID }) |
#Html.ActionLink("Borrar", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
<div>
#Html.Paging(new PagedList<Productos>(ViewData.Model.ToList(),1,10), Url.Action("Index","Index", new { page = "PAGENUM" }), "PAGENUM")
</div>
Hope you can help me, i have been stuck with this for one day, just last friday i started using mvc3, the good thing was what my boss needs is what is on the tutorial, but, now that i wanted to do this extra thing (pagedlist) i'm really lost!!

It looks as if in this line
#Html.Paging(new PagedList<Productos>(ViewData.Model.ToList(),1,10), Url.Action("Index","Index", new { page = "PAGENUM" }), "PAGENUM")
you are hardcoding the current page index to be 1.
I'd guess that in your Index action method you need might want to have something representing your current page that you can pass through to your view, and replace the hardcoded 1 with that.
e.g.
public void Index(int page = 1)
{
// ... set up your view model
// ...
// ...
// page is added to the url by your paging helper.
ViewBag.CurrentPage = page;
return View(viewModel);
}
And in the view...
#Html.Paging(new PagedList<Productos>(ViewData.Model.ToList(),#ViewBag.CurrentPage,10), Url.Action("Index","Index", new { page = "PAGENUM" }), "PAGENUM")

Based on what you said in your comment, that the paged list doesn't appear at the bottom of the page, I'd really recommend doing some debugging and seeing which code paths are actually executing. But anyway we can maybe guess the following...
First step is to put a breakpoint in the ListPaging.Paging and check it's actually getting called. If it is, and nothing at all is getting appended to your StringBuilder, then perhaps
if (pagedList.ItemCount > pagedList.PageSize)
{
// ...
is not evaluating to true. I'm assuming there's more items in your list than 10, so it should be true. So maybe the reason this isn't evaluating to true is because neither value is being set.
The constructor that you added looks dubious:
public PagedList(List<Productos> list, int p, int p_2)
{
// TODO: Complete member initialization
this.list = list;
this.p = p;
this.p_2 = p_2;
}
None of the properties that PagedList uses actually get set in here. what's the point of this constructor? What are p and p_2? If this constructor is being called, then ItemCount and PageSize will have no value. I'd suggest getting rid of it and letting the other constructors be called.

Related

List of Items always null MVC 5

I am stuck in this problem and i cannot solve it.
This is my ViewModel
public class AddOrderReceive
{
public string item_name { get; set; }
public DateTime? date_received { get; set; }
public decimal? quantity_received { get; set; }
public bool IsSelected { get; set; }
public decimal? item_rate { get; set; }
}
This is my View
#model List<newtest.Models.AddOrderReceive>
#if(Model != null && Model.Count > 0)
{
for(var i = 0; i < Model.Count; i++)
{
<tr>
#if(Model[i].quantity_remaining == 0)
{
<td colspan="6" class="text-center">Already Sent</td>
}
else
{
#Html.HiddenFor(r => Model[i].item_id)
<td>#Html.CheckBoxFor(r => Model[i].IsSelected)</td>
<td>#Html.EditorFor(r => Model[i].item_rate)</td>
}
</tr>
}
}
And finally, This is my Controller:
[HttpGet]
public ActionResult AddRAR(int? my_id)
{
try
{
var get_items = (from or in db.orders
where or.id == my_id
select new AddOrderReceive()
{
item_name = or.item_name,
quantity_received = or.quantity_receive,
date_received = or.date_receive,
order_receive_id = or.order_receive_id
}).ToList();
foreach(var t in get_items)
{
var get_remain = (from ra in db.order_detail
where ra.contract_id == t.ca_id && ra.order_receive_id == t.order_receive_id
select new
{
consump_quantity = ra.consump_quantity
});
t.quantity_remaining = t.quantity_received - get_remain.Sum(r => r.consump_quantity) ?? t.quantity_received;
}
return View(get_items);
}
catch(Exception ex)
{
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddReceivng(List<AddOrderReceive> rc_form)
{
//Some Logic
}
The problem is that whenever I post the form, it is always null. But when I remove this block:
#if(Model[i].quantity_remaining == 0)
{
<td colspan="6" class="text-center">Already Sent</td>
}
It starts working. I don't know what's the problem. I've searched everywhere but still can't figure out the problem here.
Your #if(Model[i].quantity_remaining == 0) block of code, if its executed in the first iteration, means that your collection indexers would not be zero based. The DefaultModelBinder requires that collection indexers start at zero and be consecutive.
You can override this behavior by including a hidden input for the indexer. Note also that an <input> is not a valid child of a <tr>, and should be inside a <td> element.
for(var i = 0; i < Model.Count; i++)
{
#if(Model[i].quantity_remaining == 0)
{
<td colspan="6" class="text-center">Already Sent</td>
}
else
{
<td>
<input type="hidden" name="Index" value="#i" /> // Add this
#Html.HiddenFor(r => r[i].item_id)
#Html.CheckBoxFor(r => r[i].IsSelected)
</td>
<td>#Html.EditorFor(r => r[i].item_rate)</td>
}
}

CheckBox List in ASP.net MVC3

I have an SuperVisor Form and I need to show a list of Employees with checkboxes for selection.
Once I click Save , supervisor information and the selected employees id should be saved to DB.
Which is best option to achieve this ?
Model
public class SelectEmployee
{
public int _EmployeeID;
public string _EmployeeName;
public bool _check;
public int EmployeeID { get { return _EmployeeID; } set { _EmployeeID = value; } }
public string EmployeeName { get { return _EmployeeName; } set { _EmployeeName = value; } }
public bool check { get { return _check; } set { _check = value; } }
}
public class DemoManager
{
public static List<SelectEmployee> GetSelectedEmployee()
{
DemoEntities db = new DemoEntities();
var query = (from i in db.EmployeeMasters
select new SelectEmployee { EmployeeID = i.EmployeeID, EmployeeName = i.EmployeeName, check = false }).ToList();
return query;
}
}
View
#using(Html.BeginForm())
{
<table class="table">
#for (var i = 0; i < Model.Count; i++) {
<tr>
<td>
#Html.DisplayFor(modelEmployee => modelEmployee[i].EmployeeID)
</td>
<td>
#Html.CheckBoxFor(modelEmployee => modelEmployee[i].check)
</td>
<td>
#Html.DisplayFor(modelEmployee => modelEmployee[i].EmployeeName)
</td>
</tr>
}
</table>
<input type="submit" value="click" />
}
Controller
public ActionResult Index()
{
return View(DemoManager.GetSelectedEmployee());
}
[HttpPost]
public ActionResult Index(List<SelectEmployee> emp)
{
var query = (from i in emp
where i.check == true
select i);
// Here you can set the insert statements the query will contain only selected items
return View(model);
}

.net MVC passing linq data from controller to view

I am trying to pass data from controller to view. I have searched the web but could not find a solution.
if I do this it works:
Controller:
var yyy = (from a in Connection.Db.Authorities select a) ;
ViewBag.data = yyy;
View:
#foreach(var item in ViewBag.data)
{
#item.Value
}
But the following code does not work:
Controller:
var yyy = (from a in Connection.Db.Authorities select new {Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)}) ;
ViewBag.data = yyy;
View:
#foreach(var item in ViewBag.data)
{
#item.Value
}
It gives "item does not contain a definition for Value" for the view file.
Any help would be great.
Thank you.
-edited: updated the second controller linq query. and corrected the first controller linq query.
It's because You already select Value and Value has no such property as Value. You should change in controller:
var yyy = (from a in Connection.Db.Authorities select a.Value); to
var yyy = (from a in Connection.Db.Authorities select a);
OR change the view to
#foreach(var item in ViewBag.data)
{
#item
}
//////////////////////////////////////////////// EDITS ////////////////////////////////////////////////
Than You should not use anonymous object. You should create ViewModelClass. For Example:
public class AuthoritiesViewModel
{
public string Value { get; set; }
public string TypeCode { get; set; }
public string Return { get; set; }
}
And change your controller:
var yyy = (from a in Connection.Db.Authorities select new AuthoritiesViewModel{ Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)});
ViewBag.data = yyy;
and in your view you will be able to use:
<table>
<tr>
<th>Value</th>
<th>TypeCode</th>
<th>Return</th>
</tr>
#foreach(AuthoritiesViewModel item in ViewBag.data)
{
<tr>
<td>#item.Value<td>
<td>#item.TypeCode<td>
<td>#item.Return<td>
</tr>
}
</table>
Also, I have a question to You. Why do You use ViewBag to pass data from controller to view? Why don't You use Model to pass these data to view according to MVC pattern?
//////////////////////////////////////////////// MORE EDITS ////////////////////////////////////////////////
To send more than one query result You can create more complex model. For example:
public class AuthoritiesViewModel
{
public string Value { get; set; }
public string TypeCode { get; set; }
public string Return { get; set; }
}
public class AnotherQueryViewModel
{
public string AnotherQueryValue { get; set; }
public string AnotherQueryTypeCode { get; set; }
public string AnotherQueryReturn { get; set; }
}
public class ModelClass
{
IEnumerable<AuthoritiesViewModel> Authorities { get; set; }
IEnumerable<AnotherQueryViewModel> AnotherQueryResults { get; set; }
}
And change the controller:
var yyy = (from a in Connection.Db.Authorities select new AuthoritiesViewModel{ Value = a.Value, TypeCode = a.TypeCode, Return = Calculate(a.Return)});
// do your another select
var zzz = (from smthing select new AnotherQueryViewModel ...)
// create model instance
ModelClass model = new ModelClass()
{
Authorities = yyy.AsEnumerable(),
AnotherQueryResults = zzz..AsEnumerable()
}
// return view with model
return View("view", model);
and in view you can use:
#model ModelClass
#*display first query result*#
<table>
<tr>
<th>Value</th>
<th>TypeCode</th>
<th>Return</th>
</tr>
#foreach(AuthoritiesViewModel item in Model.Authorities)
{
<tr>
<td>#item.Value<td>
<td>#item.TypeCode<td>
<td>#item.Return<td>
</tr>
}
</table>
#*display second query result*#
<table>
<tr>
<th>Another Query Value</th>
<th>Another Query TypeCode</th>
<th>Another Query Return</th>
</tr>
#foreach(AnotherQueryViewModel item in Model.AnotherQueryResults)
{
<tr>
<td>#item.AnotherQueryValue<td>
<td>#item.AnotherQueryTypeCode<td>
<td>#item.AnotherQueryReturn<td>
</tr>
}
</table>
use sth like this
ViewBag.qualification = new SelectList(db.Lookups.Where(x => x.lookup_type == "Qualification"), "lookup_content", "lookup_content");

Issue with a single razor view accessing two models (ASP.NET MVC3)

View(Index.chtml) is returning 0 rows while accessing two models in the view. Please see the code below. I am new to ASP.NET and I am still learning. I tried to debug and I see the table data is not being passed to correctly. Please help
================================================================================
Controller: (OrganizationCodesController.cs)
================================================================================
namespace MvcProject.Controllers
{
public class OrganizationCodesController : Controller
{
//
// GET: /OrganizationCodes/
public ActionResult Index()
{
List<TABLE_CODES> temp_codes = new List<TABLE_CODES>();
List<TABLE_ORGANIZATIONS> temp_organizations = new List<TABLE_ORGANIZATIONS>();
var viewModel = new OrganizationCodesModel(temp_codes, temp_organizations);
return View(viewModel);
}
}
============================================================================
Model: (OrganizationCodesModel.cs)
============================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
namespace MvcProject.Models
{
public class OrganizationCodesModel
{
public List<TABLE_CODES> TABLE_CODES { get; set; }
public List<TABLE_ORGANIZATIONS> TABLE_CODES { get; set; }
public OrganizationCodesModel(List<TABLE_CODES> _codes, List<TABLE_ORGANIZATIONS> _organizations)
{
TABLE_CODES = _codes;
TABLE_ORGANIZATIONS = _organizations;
}
}
}
========================================================================
View: (Index.chtml)
========================================================================
#model MvcProject.Models.OrganizationCodesModel
<table>
<thead>
<tr>
<th>
ORGANIZATION_NAME
</th>
<th>
RANK
</th>
<th>
LEVEL
</th>
</thead>
<tbody>
#foreach (var item in Model.TABLE_CODES) {
<tr>
<td>
#foreach (var item_1 in Model.TABLE_ORGANIZATIONS)
{
if (item.LOCATION == item_1.ID)
{
#item1.NAME
break;
}
}
</td>
<td>
#item.RANK
</td>
<td>
#item.LEVEL
</td>
</tr>
}
</tbody>
</table>
List<TABLE_CODES> temp_codes = new List<TABLE_CODES>();
List<TABLE_ORGANIZATIONS> temp_organizations = new List<TABLE_ORGANIZATIONS>();
var viewModel = new OrganizationCodesModel(temp_codes, temp_organizations);
your instanciating two empty lists...
you should put something in your lists !
something like
List<TABLE_CODES> temp_codes = GetTempCodesFromSomewhere();
or
List<TABLE_CODES> temp_codes = new List<TABLE_CODES> {
new TABLE_CODES {LOCATION = 1, RANK = 1, LEVEL =1},
new TABLE_CODES{LOCATION = 2, RANK = 3, LEVEL = 12345}
};
Modiy your Model Class like this:
public class OrganizationCodesModel
{
public List<TABLE_CODES> listTABLE_CODES { get; set; }
public List<TABLE_ORGANIZATIONS> listTABLE_ORGANIZATIONS { get; set; }
}
I have also added text "list" as prefix to the name of the list to distinguish it from the class name otherwise both list name and class name are same.
Ok Now you have to also modify your Index action method like this:
public ActionResult Index()
{
OrganizationCodesModel model = new OrganizationCodesModel();
List<TABLE_CODES>listCodes = new List<TABLE_CODES> {
new TABLE_CODES {LOCATION = 1, RANK = 1, LEVEL =1},
new TABLE_CODES{LOCATION = 2, RANK = 3, LEVEL = 12345}
};
List<TABLE_ORGANIZATIONS> listOrganisation = new List<TABLE_ORGANIZATIONS> {
new TABLE_ORGANIZATIONS {ID = 1,NAME="ABC"},
new TABLE_ORGANIZATIONS{ID = 2,NAME="XYZ"}
};
model.ListTABLE_CODES = listCodes;
model.ListTABLE_ORGANIZATIONS = listOrganisation;
return View(model);
}
and in your View just replace your List name like this:
#foreach (var item in Model.listTABLE_CODES )
#foreach (var item_1 in Model.listTABLE_ORGANIZATIONS )
That is all. Now you will be able to see your output like this:

asp net mvc3 post a list of objects to action

I created a page with aspnet mvc3. It show all users info as a list. I want to do something with this list. There are some checkboxes that belong to each items. When I click some checkboxes and press submit button, I want to post the whole list as a collection and save each items of this collection to database. There are several notes on internet but there is no exact solution. I have a UserDto. and want to use this to transfer users data in all sections.
Does anyone have any full solution about this or can they give any idea?
Thanks in advance.
Kerem
I added some of my codes. You can see the lead sentences what they are about.
this is my index view detail:
#model List<DomainModel.UserApprovalDto>
#{
ViewBag.Title = "Manage Users";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Manage Users</h2>
<div>#Html.Partial("_PartialManageUsers", (List<DomainModel.UserApprovalDto>)Model) </div>
this is my partial view detail:
#model List<DomainModel.UserApprovalDto>
#using (Html.BeginForm("ConfirmUsers", "ManageUsers", FormMethod.Post))
{
<table>
<tr>
<th>
Name
</th>
<th>
Is Reported
</th>
</tr>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[i].FirstName)
</td>
<td>
#Html.CheckBox("IsReported", Model[i].IsReported.HasValue ? Model[i].IsReported.Value : false)
#*#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);*# #* #if (Model[i].IsReported != null)
{
#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);
}
else
{
#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);
}*#
</td>
<td>
</td>
</tr>
}
</table>
<div>
<input name="submitUsers" type="submit" value="Save" />
</div>
}
this is my controller submit method
[HttpPost]
public ActionResult ConfirmUsers(List<DomainModel.UserApprovalDto> collection)
{
if (ModelState.IsValid)
{
//TO-DO
}
return RedirectToAction("Index");
}
this last one is my DTO class detail:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DomainModel
{
public class UserApprovalDto
{
public long UserId { get; set; }
public Guid CarUserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhotoPath { get; set; }
public string PhotoSmallPath { get; set; }
public string PhotoSquarePath { get; set; }
public string PhotoBigPath { get; set; }
public bool IsBlocked { get; set; }
public bool IsDeleted { get; set; }
}
}
when I submit this code my list return null collection to my controller method.
thanks for your comments.
Assuming you are creating a screen which adds/ remove users to a course. So let's create some viewmodels
public class CourseVM
{
public string Name { set;get;}
public int CourseID { set;get;}
public List<UserVM> Users { set;get;}
public CourseVM()
{
Users=new List<UserVM>();
}
}
public class UserVM
{
public string Name { set;get;}
public int UserID{ set;get;}
public bool IsSelected { set;get;}
}
Now in your GET Action, you will fill the values of the ViewModel and sent it to the view.
public ActionResult Add()
{
var vm = new CourseVM();
//The below code is hardcoded for demo. you may replace with DB data.
vm.Users.Add(new UseVM { Name = "Jon" , UserID=1});
vm.Users.Add(new UseVM { Name = "Scott", UserID=2 });
return View(vm);
}
Now Let's create an EditorTemplate. Go to Views/YourControllerName and Crete a Folder called "EditorTemplates" and Create a new View there with the same name as of the Property Name(UserVM.cshtml)
Add this code to your new editor template.
#model ChannelViewModel
<p>
<b>#Model.Name</b> :
#Html.CheckBoxFor(x => x.IsSelected) <br />
#Html.HiddenFor(x=>x.Id)
</p>
Now in your Main View, Call your Editor template using the EditorFor Html Helper method.
#model CourseVM
#using (Html.BeginForm())
{
<div>
#Html.EditorFor(m=>m.Users)
</div>
<input type="submit" value="Submit" />
}
Now when you post the form, Your Model will have the Users Collection where the Selected Checkboxes will be having a True value for the IsSelected Property.
[HttpPost]
public ActionResult Add(CourseVM model)
{
if(ModelState.IsValid)
{
//Check for model.Users collection and Each items
// IsSelected property value.
//Save and Redirect(PRG pattern)
}
return View(model);
}

Resources