How to paginate on a parameterized list in MVC? - asp.net-mvc

I want to paging in Product list with parameter Category, i using PagedList mvc
controller sample
public ActionResult ListProduct(int id, int? pagePos)
{
var list = db.List_Product.Where(e => e.CategoryID == id);
int pageNumber = (pagePos ?? 1);
return View(list.ToList().ToPagedList(pageNumber, 2));
}
and in view ListProduct.cshtml
#*#model IEnumerable<Sales.Areas.Users.Models.List_Product>*#
#model PagedList.IPagedList<sales.areas.users.models.list_product> #*Maybe error in line here*#
#using PagedList.Mvc
<table class="table">
<tr>
<th>
Name
</th>
<th>
ID
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
</tr>
}
</table>
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, pagePos => Url.Action("ListProduct", new { pagePos }))
It's not working, and get this error CS0234: The type or namespace name 'IPagedLis' does not exist in the namespace 'PagedList' (are you missing an assembly reference?) although i had added reference PagedList ago.

Without more informations about the error is hard to find the culprit. You should disable custom errors and activate debug in your web.config
First check that the variable id in ActionResult ListProduct is passed.
Then in your view change:
#model PagedList.IPagedList<sales.areas.users.models.list_product>
With:
#model PagedList.IPagedList<Sales.Areas.Users.Models.List_Product>

Make sure that all necessary namespaces come before the use of any types in that namespace
#using PagedList; //import this so we can cast our list to IPagedList (only necessary because ViewBag is dynamic)
#using PagedList.Mvc; //import this so we get our HTML Helper
#model IPagedList<Sales.Areas.Users.Models.List_Product>

Related

Bind viewmodel to partial view

I have a model, which can represent 3 categories. I want in my view, make 3 different tables for each category with relevant fields. I think for this I need to use partial view with viewmodel for each category.
So my main model is "Ad", which have 3 sub viewmodels (Realty, Auto and Service).
Here the example how I implement Realty action on my home controller:
public ActionResult Realty()
{
var ads = db.Ads.Include(a => a.Realty);
var vm = new List<RealtyViewModel>();
foreach (var ad in ads)
{
vm.Add(new RealtyViewModel
{
Title = ad.Title,
Descirpiton = ad.Descirpiton,
Type = ad.Realty.Type,
NumberOfRooms = ad.Realty.NumberOfRooms
});
}
return PartialView(vm);
}
Then my partial view, looks like this:
#model IEnumerable<OGAS.Areas.Category.ViewModels.RealtyViewModel>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Type)
</th>
<th>
#Html.DisplayNameFor(model => model.Descirpiton)
</th>
<th>
#Html.DisplayNameFor(model => model.NumberOfRooms)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Type)
</td>
<td>
#Html.DisplayFor(modelItem => item.Descirpiton)
</td>
<td>
#Html.DisplayFor(modelItem => item.NumberOfRooms)
</td>
</tr>
}
</table>
Then in my Index page (without using any models), I call partial view like this:
#{Html.RenderPartial("Realty");}
But then I'm getting following error:
An exception of type 'System.NullReferenceException' occurred in App_Web_gdyh352c.dll but was not handled in user code
Could you please advise if this approach is good (calling 3 vms), if yes how to implement this?
Thanks.
Try to replace #{Html.RenderPartial("Realty");} and use #Html.Action("Realty") in this case, as you need to call back to the controller action, in order to create the model for the partial view.
See MVC Html.Partial or Html.Action for more information.
Use this, for .net core and mvc. #Html.Action has been removed from .net core
#await Html.PartialAsync("_YourPartialViewName", YourModel)

Partial View is not rendering td elements inside foreach razor tag

I am using a List of Products as a Model for my Partial view. In the partial view I am using a foreach loop to get the values of Product class and trying to render it to users. In the partial view I've written this code:
#model Project.ViewModel.ListofProductsVM
#using Project.Models
<table>
<tr>
<th>
Name
</th>
<th>
Cost
</th>
</tr>
#{
foreach (Products prod in Model.products)
{
<tr>
<td>#prod.Name.ToString()</td>
<td>#prod.Cost.ToString()</td>
</tr>
}
}
</table>
I can see the headers "Name" and "Cost" in the page but Product Name and its Cost is not rendering. When I am checking the source code in HTML it is showing me this HTML only:
<table>
<tr>
<th>
Name
</th>
<th>
Cost
</th>
</tr>
</table>
While debugging I can see the values are correctly getting passed to Partial Views. Even the "#prod.Name" and "#prod.Cost" is showing me the correct value. But it is not rendering it to HTML. I don't understand what I am doing wrong here. Thanks in advance.
The #{ } means that this is c# code block, you can fix the problem by writing your foreach loop code this way:
#foreach (Products prod in Model.products)
{
<tr>
<td>#prod.Name.ToString()</td>
<td>#prod.Cost.ToString()</td>
</tr>
}
and if you want to stick with your way then you have to specify to render that as html like:
#{
foreach (Products prod in Model.products)
{
#:<tr>
#:<td>#prod.Name.ToString()</td>
#:<td>#prod.Cost.ToString()</td>
#:</tr>
}
}
I had a similiar problem. In my case, all I needed was to add "#" before the foreach nested in an if statement. This is a pared down snippet of my working code
C# Model class:
public class MyModel
{
public string FirstName{ get; set; }
public string LastName{ get; set; }
}
CSHTML file:
#model List<MyProject.Models.MyModel>
#if (Model.Count > 0)
{
<div class="row" >
<table>
#foreach (var item in Model)
{
<tr>#item.FirstName #item.LastName</tr>
}
</table>
</div>
}
But it's the same answer that another user gave you.

How to remain/retain on the same page when using PagedList.mvc

I am using PagedList.Mvc and I have added a nice way to navigate across various pages in a mvc web application. However, when I click on an "edit" or "details" tab and save changes I am sent back to the 1st page. I want to remain on the same page where the changes were made.
Here is the code I have in the controller:
// GET: Item
public ActionResult Index(int? page)
{
var items = db.Items.Include(i => i.PurchaseOrder);
return View(items.ToList().ToPagedList(page ?? 1, 3));
}
Here is the code I have in the view:
#using PagedList;
#using PagedList.Mvc;
#model IPagedList<PurchaseOrders.Models.Item>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.First().ItemDescription)
</th>
<th>
#Html.DisplayNameFor(model => model.First().Quantity)
</th>
<th>
#Html.DisplayNameFor(model => model.First().Price)
</th>
<th>
#Html.DisplayNameFor(model => model.First().DueDate)
</th>
<th>
#Html.DisplayNameFor(model => model.First().DateReceived)
</th>
<th>
#Html.DisplayNameFor(model => model.First().Comments)
</th>
<th>
#Html.DisplayNameFor(model => model.First().PurchaseOrder.PurchaseRequest_)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ItemDescription)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.DisplayFor(modelItem => item.DueDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateReceived)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments)
</td>
<td>
#Html.DisplayFor(modelItem => item.PurchaseOrder.PurchaseRequest_)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ItemId }) |
#Html.ActionLink("Details", "Details", new { id=item.ItemId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ItemId })
</td>
</tr>
}
</table>
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }))
Please help!
You could pass an additional 'page` parameter to your edit method, for example
In your Index method, add
ViewBag.CurrentPage = page; // or use a view model property
Then your link would be
#Html.ActionLink("Edit", "Edit", new { id=item.ItemId, page = ViewBag.CurrentPage})
Then your edit method
[HttpGet]
public ActionResult Edit(int ID, int page)
{
ViewBag.CurrentPage = page; // pass current page to edit view
And your edit view
#using (Html.BeginForm(new { page = ViewBag.CurrentPage })) {
And in you post method
[HttpGet]
public ActionResult Edit(EditModel model, int page)
{
.... // Save
return RedirectToAction("Index", new { page = page });
In this case the page is stored in the ViewBag which makes it ephemeral (the ViewBag is only available for the current request).
In the controller, you're telling it if you get null use 1 as your current page. so null is always retuned and you get the 1st page everytime.
You need to provide the current page Number to your views that you navigate to (Edit/Create) and then provide it back to the original page when you're done.
You can use the TempData,that works well on HTTP redirects and lives longer than viewbag or viewData.
You can also move it arround with your models when calling actions and then give it back to the index action that needs a page number.
You can use sessions too. BTW, TempData is using session behind the scenes.
UPDATED:
Code to add in your index action:
var page = TempData["page"];
Code to add in the Create or Edit Submit action
//Get the page number
var page = TempData["page"];
//Set it back to Tempdata (because Tempdata is only for redirects) otherwise it will be lost
TempData["page"]=page;
add the value of the parameter to TempData["page"] when calling back the index action again
You can also access it from Index action directly since we repopulated it:
var page = TempData["page"];
return View(items.ToList().ToPagedList(page ?? 1, 3));
I also had this problem.
I tried to put it in the URL at first but it seems a bit weird to have ?page=2 in our URL.
So I replaced it with using TempData
What you need to do is this:
Store the page in TempData when you are in your Index() action method;
public const string PAGE_QUERY_STRING_KEY = "page";
public ActionResult Index(int page = 1)
{
TempData[PAGE_QUERY_STRING_KEY] = page;
...
}
Then use TempData.Peek(), instead of TempData[], everywhere else (to retain the value of your page between requests which are related to your current Index page) --- in your Edit, Create, Details, etc. action methods:
public ActionResult Edit(...)
{
...
return RedirectToAction(nameof(Index), new { page = TempData.Peek(PAGE_QUERY_STRING_KEY) });
// do not do this because this will remove the temp data
// return RedirectToAction(nameof(Index), new { page = TempData[PAGE_QUERY_STRING_KEY])
}
... and in your views:
<!--(Edit.cshtml)-->
...
<p>
#Html.ActionLink("Back to List", "Index",
new { page = TempData.Peek(FLP.Web.Controllers.UsersAdminController.PAGE_QUERY_STRING_KEY) })
</p>

C# MVC4 Partial View with other ActionResult in Controller

i have a problem.
I have my Controller "DashboardNB2Controller", my View "index.cshtml" and i want to integrate a partial view called "_PartialView.cshtml" in my "index.cshtml". Both Views are in the same folder. In my controller, i have the "ActionResult _PartialView" for a databaseoperation in my partial view.
But if I integrate my partial view in my index view, the action result "_PartialView" didn't work. I get no results. The query for my database is correct. I checked this.
Here are my codes
My Controller with the ActionResult for the Partial View
public ActionResult _PartialView()
{
var lastMessages= (from t in db.view_tbl_message
orderby t.Date descending
select t).Take(10);
ViewModelDashboard model = new ViewModelDashboard();
model.view_tbl_message = lastMessages.ToList();
return PartialView("_PartialView", model);
}
My index.cshtml
#model AisWebController.Areas.Statistics.Models.ViewModelDashboard
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<br />
#{Html.Action("_PartialView", "DashboardNB2");}
<br />
And my _PartialView.cshtml
#model WebApplication.Areas.Stats.Models.ViewModelDashboard
<table class="table table-bordered">
<tr>
<th>
Date
</th>
<th>
User
</th>
<th>
Message
</th>
</tr>
#foreach (var item in Model.view_tbl_message)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date
</td>
<td>
#Html.DisplayFor(modelItem => item.User)
</td>
<td>
#Html.DisplayFor(modelItem => item.Message)
</td>
</tr>
}
</table>
If someone can help - that would be aweseome!
Change
#{Html.Action("_PartialView", "DashboardNB2");}
to
#Html.Action("_PartialView", "DashboardNB2")
You don't need {} brackets after you have # in view for Html extension methods
Look your #Html.DisplayFor it doesn't have any {} brackets.
Same applies for #Html.ActionLink

How to display a collection in View of ASP.NET MVC Razor project?

How to display a collection in View of ASP.NET MVC Razor project?
My Model and View is below. For one person i've to display Many tests on the screen. Thanks in Advance
namespace UI.Models
{
public class SuperStudent
{
public string FullName { get; set; }
public ICollection<TestDetail> CandidateTestDetails { get; set; }
}
public class TestDetail
{
public DateTime TestDate { get; set; }
public string RegNum { get; set; }
}
}
View
#model IEnumerable<UI.Models.SuperStudent>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FullName)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
Print all test details
</td>
</tr>
}
</table>
For one person your view must be like :
#model UI.Models.SuperStudent
<h2>#Model.FullName</h2>
<table class="table">
<tr>
<th>
TestDate
</th>
<th>
RegNum
</th>
</tr>
#foreach (var item in Model.CandidateTestDetails ) {
<tr>
<td>
#item.TestDate
</td>
<td>
#item.RegNum
</td>
</tr>
}
</table>
The code works the same inside a loop as it does outside the loop. Just reference the loop item. For example:
#foreach (var student in Model) {
#foreach (var test in student.CandidateTestDetails) {
<tr>
<td>#test.RegNum</td>
</tr>
}
}
That would output just the RegNum value. You can also make use of things like DisplayNameFor by referencing an element in the collection:
#foreach (var student in Model) {
#foreach (var test in student.CandidateTestDetails) {
<tr>
<td>
#Html.DisplayNameFor(model => student.CandidateTestDetails.First().RegNum)<br />
#test.RegNum
</td>
</tr>
}
}
While intuitively it may seem that this could fail if Model is empty (since First() would throw an exception), it doesn't actually execute First() on the collection. The engine simply uses that to reflect into the model returned by First() to determine the display name.
Given this, you can construct the markup however you wish for those items. If it's complex enough, you might even create a partial view for just an item in that collection and render that partial view in the loop by passing the item value to the partial view.

Resources