Related
Please do not mark this as a duplicate because I've already checked these but none of them helped me.
Sequence contains no elements?
Using a PagedList with a ViewModel ASP.Net MVC
I'm trying to use pagedList in my asp.net mvc project but it's giving me "Sequence contains no elements?" when I click on page numbers.
First I have 2 Table Products and Images.
Product Contains: ProductID - ProductName - ProductDescription.
Images contains :ImageID - ImagePath - ProductFK
I have a viewModel That contains these 2 tables
public class myViewModel
{
public IPagedList<Products> myProducts { get; set; }
public IPagedList<Images> myImages{ get; set; }
}
In my Search View I have this.
#model PagedList.IPagedList<myViewModel>
#using PagedList;
#using PagedList.Mvc;
<div>
<input type="text" name="search">
<button type="submit">Search</button>
</div>
#foreach (Products item in Model.First().myProducts)
{
#item.ProductName
#item.ProductDescription
}
<div>
// Page Index
#(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model.First().myProducts, page => Url.Action("Search", new { page, search = Request.QueryString["search"] }), PagedListRenderOptions.PageNumbersOnly)
And Here's my search method in my home controller
public ActionResult Search(string search, int? page)
{
int pageSize = 3;
int pageNumber = (page ?? 1);
var Items= new[] {
new myViewModel { myProducts = DB.Products.Where(a=>a.ProductName.Contains(search)).OrderByDescending(a=>a.ProductID).ToPagedList(pageNumber,pageSize),
}
};
return View(Items.ToPagedList(pageNumber, pageSize));
}
The search worked great and even the page index is giving me the number of pages depending on my search results(meaning that if I have a product with a name="abc" and I have 9 abc products in my table, if I'm showing 3 element only in each page ,Im getting 1,2,3 for page indexing.)
The only thing the goes wrong is when I click on a page number to navigate to other results, it gives me "Sequence contains no elements".
Please if someone can help me, it would be so appreciated .
I have created a search page which returns a list of objects to be displayed on a webgrid. I am using the webgrids default paging. The problem arises when I try to page to the second page of search results - I am taken back to the search page. How do I use the deafult paging functionality of the razor webgrid and achieve paging through search results ?
Actionmethod :
[HttpPost]
public ActionResult GetEmails(UserResponse response )
{
if (response.RefId != null)
{
int refID = Convert.ToInt32(response.RefType);
var query = from c in db.tb_EmailQueue
where c.ReferenceTypeId == refID && c.ReferenceId.Contains(response.RefId)
select c;
var results = new List<tb_EmailQueue>();
results.AddRange(query);
return View("Index", results);
}
return View();
}
Search Page View :
<body>
#using (Html.BeginForm())
{
#Html.DropDownListFor(x=> x.RefType, (IEnumerable<SelectListItem>) ViewBag.Categories,"Please select reference type")
<br/>
<p>Reference Type</p>
#Html.TextBoxFor(x => x.RefId)
<input type ="submit" value="Submit" />
}
#using (Html.BeginForm())
{
#Html.TextBoxFor(x=>x.Date, new{#id="example1"})
<input type ="submit" value="Submit" />
<br/>
}
Results Display View :
#{
if (Model.Any())
{
var grid = new WebGrid(Model, canPage: true, rowsPerPage: 100);
#grid.GetHtml(tableStyle: "table table-striped table-bordered", columns: grid.Columns(
grid.Column(header: "EmailQueueId",
columnName: "EmailQueueId",
format: item => Html.ActionLink(((int) item.EmailQueueId).ToString(), "Details", new {id = item.EmailQueueId})),
grid.Column("QueueDateTime", canSort: true, format: #<text>#item.QueueDateTime.ToString("dd/MM/yy H:mm:ss")</text>),
grid.Column("ReferenceTypeID"),
grid.Column("ReferenceID"),
grid.Column(header: "ToList",
columnName: "ToList",
format: #<input type ="text" value="#item.ToList" title="#item.ToList" readonly="readonly"/>),
grid.Column(header: "Subject",
columnName: "Subject",
format: #<input type ="text" value="#item.Subject" title ="#item.Subject" readonly="readonly"/>),
grid.Column("FailureCount")
))
}
else
{
<p>No records</p>
}
}
Since you get back what page number being asked for, and you know how many results you're looking for, you're just missing a piece to your LINQ query. I don't use the SQL syntax, so please excuse this, though it should be easily translatable to your methodology.
var query = (from c in db.tb_EmailQueue
where c.ReferenceTypeId == refID && c.ReferenceId.Contains(response.RefId)
select c).Skip((pageNumber - 1) * pageSize).Take(pageSize);
You want (pageNumber - 1) because your pageNumber will be 1-based, and if you're looking for the first page, you don't want to skip anything (0 * pageSize). With those results, you just want to Take() however many are going to be displayed on the page.
The problem of paging and sorting with WebGrid a filtered subset of a table has been solved for the ASP.NET Web Pages framework by Mike Brind in this article: Displaying Search Results In A WebGrid.
I have tried to translate it in MVC, but I am more comfortable with Web Pages, so be tolerant.
Controller
public ActionResult Customers(string country)
{
var search = (country == null ? "" : country);
NORTHWNDEntities db = new NORTHWNDEntities();
var query = from c in db.Customers
where c.Country.Contains(search)
select c;
var results = new List<Customers>();
results.AddRange(query);
return View("Customers", results);
}
View
#{
var grid = new WebGrid(Model, rowsPerPage:5);
}
<hgroup class="title">
<h1>Customers</h1>
</hgroup>
<section id="searchForm">
#using (Html.BeginForm()){
<p>
Country: #Html.TextBox("Country", #Request["Country"])
<input type="submit" />
</p>
}
</section>
<section>
<div>
#grid.GetHtml(columns:grid.Columns(
grid.Column(columnName:"CompanyName",header:"Name"),
grid.Column(columnName:"Address"),
grid.Column(columnName:"City"),
grid.Column(columnName:"Country")
))
</div>
</section>
#section scripts{
<script type="text/javascript">
$(function(){
$('th a, tfoot a').on('click', function () {
$('form').attr('action', $(this).attr('href')).submit();
return false;
});
});
</script>
}
I have used the Northwind sample db; if you want to use my same db, you can find it at this link.
The solution keeps the search form and the WebGrid in the same page, because every time you change pagination or sort order, you must repost the search criteria to filter the table.
According with Mike Brind, "The answer to the problem lies in the snippet of jQuery that appears in the script section. A handler is attached to the onclick event of the links in the table head and table foot areas - or the sorting and paging links. When they are clicked, the value of the link is obtained and provided to the form's action attribute, then the form is submitted using POST, and the GET request is cancelled by return false. This ensures that paging and sorting information is preserved in the Request.QueryString collection, while any form field values are passed in the Request.Form collection."
I'm making a newsfeed project in Visual Studios, MVC 3, Razor engine and I'm trying only to display, let's say 10, number of feeds at once.
Currently while I was getting the database going I used this index.cshtml:
#model IEnumerable<NyjiGrunnur.Models.Article>
#{
ViewBag.Title = "NewsFeed";
}
<h2>#ViewBag.Message</h2>
#foreach (var item in Model)
{
<div id="eitt">
<fieldset>
<legend>#Html.ActionLink( item.Name, "Edit", new { id=item.Id } )</legend>
<div>#item.Subject, #item.Created</div>
<p>#Html.Raw(item.Content.Replace(Environment.NewLine, "<br/>"))</p>
</fieldset>
</div>
}
The foreach takes every single item and I was wondering if I could use a for loop or something similar to display only the 10 newest feeds.
Thanks in advance.
You can keep a counter variable and check it before displaying the data
#{
int counter=0;
}
foreach (var item in Model)
{
counter++;
if(counter<=10)
{
<div id="eitt">#item.Name</div>
}
}
But it is better to do this at your Action method and return only 10 items to the view so that you don't need to contaminate your view by adding the if statement. You can use the Take method from LINQ to get the 10 items.
public ActionResult Newsfeed()
{
List<Article> articleList=new List<Article>();
articleLsit=GetListOfItemsFromSomewhere();
//now get only 10. you may apply sorting if needed
articleList=articleList.Take(10);
return View(articleList);
}
it will be better
#foreach (var item in Model.Take(10))
{
<div id="eitt">
<fieldset>
<legend>#Html.ActionLink( item.Name, "Edit", new { id=item.Id } )</legend>
<div>#item.Subject, #item.Created</div>
<p>#Html.Raw(item.Content.Replace(Environment.NewLine, "<br/>"))</p>
</fieldset>
</div>
}
What I am trying to achieve is hard to explain, so please let me know if I can provide more information. I have a feeling that I am trying to use WebGrids beyond their means, so if anyone has any open source alternatives that would do what I am trying, that would also be helpful.
I need to build a WebGrid from the ground up, because the content returned to it (columns and values) changes depending on other criteria on my form. I have this working in a few simple lines of code in a Table, but I wanted to use WebGrid for the styling, sorting and paging.
#model DocumentSearchViewModel
#if ((this.Model != null) && (this.Model.SearchResults != null) && (this.Model.SearchResults.Count() > 0))
{
<table>
<thead>
<tr>
<th>Document</th>
#foreach (var metadata in this.Model.SearchResults.Metadata)
{
<th>
#metadata.InstanceFieldName
</th>
}
</tr>
</thead>
<tbody>
#foreach (var document in this.Model.SearchResults)
{
<tr>
<td>
#Html.ActionLink(document.Id.ToString(), "Details", new { id = document.Id })
</td>
#foreach (var metadata in document.Metadata)
{
<td>
#metadata.Value
</td>
}
</tr>
}
</tbody>
</table>
}
So to explain the model structure, The SearchResults has an IEnumerable<MetadataModel>, and this MetadataModel has properties of InstanceFieldName and Value. When a search is performed, every result will always have the same number of Metadata, and the same InstanceFieldNames, but different values, however a quick change of a field on the form, and a new search could return a new set of results (Again with the same set of Metadata as each other, but different to the first set of results)
The columns of the grid correspond to the Metadata InstanceFieldName, and the content the Value.
So I have made my best attempt using WebGrid, but the best I can get is a grid with the right column headers, and the right number of rows, the columns have the right data, but each row is the same (copied from the last row).
#{
var grid = new WebGrid(canPage: true, canSort: true, rowsPerPage: Model.PageSize, sortFieldName: Model.Sort, sortDirectionFieldName: Model.SortDir);
grid.Bind(Model.SearchResults, rowCount: Model.DocumentCount);
List<WebGridColumn> cols = new List<WebGridColumn>();
foreach(var metadata in Model.SearchResults.Select(r => r.Metadata).FirstOrDefault())
{
var col = new WebGridColumn();
col.ColumnName = metadata.InstanceFieldName;
col.Header = metadata.InstanceFieldHeader;
col.Style = "gridRow";
col.CanSort = true;
cols.Add(col);
}
foreach (var result in Model.SearchResults)
{
foreach (var col in cols)
{
var metadataValue = result.Metadata.Single(m => m.InstanceFieldName == col.ColumnName).Value;
col.Format = (item) => #Html.Raw("<text>" + metadataValue + "</text>");
}
}
}
#if ((this.Model != null) && (this.Model.SearchResults != null) && (this.Model.SearchResults.Count() > 0))
{
#grid.GetHtml(htmlAttributes: new { id = "documentGrid" }, rowStyle: "gridRow", alternatingRowStyle: "gridRowAlt", columns: cols)
}
What I'm trying to work out is how and if possible to generate the columns first, and then populate the rows into these columns.
Any help is really appreciated, thanks, Mark
You are feeding the rows with the same value, you should change the Format:
col.Format = (item) => #Html.Raw(item.metadataValue);
In MVC3, how do you create alternating row colors on a #foreach list when using the Razor view engine?
#foreach (var item in Model) {
<tr>
<td>#item.DisplayName</td>
<td>#item.Currency</td>
<td>#String.Format("{0:dd/MM/yyyy}", item.CreatedOn)</td>
<td>#String.Format("{0:g}", item.CreatedBy)</td>
<td>#Html.ActionLink("Edit", "Edit", new { id = item.Id })</td>
</tr>
}
Assuming you would rather not use CSS (i.e. :nth-child(odd)) you can either:
use a normal for loop:
#for (int i = 0; i < Model.Count; i++)
{
...
}
use .Select:
#foreach (var item in Model.Select((x, i) => new { Data = x, Index = i }))
{
...
}
Either way, you'd have access to the current index and could then use i % 2 == 1 as the condition for your background-color. Something like:
<tr style="background-color:#(i % 2 == 1 ? "red" : "white")">...</tr>
This is what CSS is for (changing style rather than content). Save the server the effort: Do it on the client.
Since you're using Razor, you can use JQuery. Here's how I do it in my projects:
$(document).ready(function () {
$("table > tbody tr:odd").css("background-color", "#F7F7F7");
}
With ASP.NET MVC 3 and the new #helper syntax, there is a neater way to handle this.
First add this #helper method:
#helper AlternateBackground(string color) {
if (ViewBag.count == null) { ViewBag.count = 0; }
<text>style="background-color:#(ViewBag.count % 2 == 1 ? color : "none")"</text>
ViewBag.count++;
}
Then just add the call to the helper in your <TR> element
#foreach (var item in Model) {
<tr #AlternateBackground("Red")>
<td>#item.DisplayName</td>
<td>#item.Currency</td>
<td>#String.Format("{0:dd/MM/yyyy}", item.CreatedOn)</td>
<td>#String.Format("{0:g}", item.CreatedBy)</td>
<td>#Html.ActionLink("Edit", "Edit", new { id = item.Id })</td>
</tr>
}
You could always do it in pure css using:
TABLE.test tr:nth-child(even)
{
background-color: #EFEFEF;
}
How about something like this?
#for (int i = 0; i < Model.length; i++) {
<tr #(i % 2 != 0 ? class="odd" : "")>
<td>#Model[i].DisplayName</td>
<td>#Model[i].Currency</td>
<td>#String.Format("{0:dd/MM/yyyy}", Model[i].CreatedOn)</td>
<td>#String.Format("{0:g}", Model[i].CreatedBy)</td>
<td>#Html.ActionLink("Edit", "Edit", new { id = Model[i].Id })</td>
</tr>
#{
int i = 0;
foreach (Account acct in Model)
{
<div class="row #(i%2==0?"even":"odd")">
#acct.name
</div>
i++;
}
}
Original: http://15daysofjquery.com/table-striping-made-easy/5/
Author: Jack Born
jQuery Zebra_Striping_Made_Easy
=============== Java script ===================
$(document).ready(function () {
$('.stripeMe tr:even').addClass('alt');
$('.stripeMe tr').hover(
function () {
$(this).addClass("highlight");
},
function () {
$(this).removeClass("highlight");
});
});
================= css =================
tr.alt td {
background-color : #F7F7F7;
}
tr.highlight td {
background-color : #bcd4ec;
}
=============== HTML ===============
<table class="stripeMe">
There isn't much documentation on it, but the Loop Helper (http://nuget.org/Packages/Packages/Details/Loop-Helper-for-WebMatrix-0-1) gives you support for detecting Even/Odd/etc. items.
What you can do is to set a variable odd outside of the foreach()
#{
var odd = false;
}
And then, inside your foreach loop, you'd change the value of it and then use it in an if condition to set the alternating classes.
#foreach (var item in Model) {
odd = !odd;
<tr class="#(odd ? "odd" : "even")">
<td>#item.DisplayName</td>
<td>#item.Currency</td>
<td>#String.Format("{0:dd/MM/yyyy}", item.CreatedOn)</td>
<td>#String.Format("{0:g}", item.CreatedBy)</td>
<td>#Html.ActionLink("Edit", "Edit", new { id = item.Id })</td>
</tr>
}
An old post, but none of the answers covered this approach, so I will.
Since you are using MVC Razor utilizing the #helper function is the simplest, cleanest and best approach.
In the App_Code folder of your project add new item or modify your existing CustomeHelpers.cshtml file with the following code:
#helper AlternateBackground(string color, Int32 iViewBagCount) {
if (iViewBagCount == null) { iViewBagCount = 0; }
<text>style="background-color:#(iViewBagCount % 2 == 1 ? color : "none")"</text>
iViewBagCount++;
}
Then on your view your foreach loop would look like this:
#foreach (var item in Model) {
<tr #CustomHelpers.AlternateBackground("#ECEDEE", Model.Count())>
<td>#item.DisplayName</td>
<td>#item.Currency</td>
<td>#String.Format("{0:dd/MM/yyyy}", item.CreatedOn)</td>
<td>#String.Format("{0:g}", item.CreatedBy)</td>
<td>#Html.ActionLink("Edit", "Edit", new { id = item.Id })</td>
</tr>
}
You can pass a color identifier like "#ECEDEE" or the named color "Blue".
This way you only have to add the #Helper function once and it propagates throughout your application and it can be called on each view as needed by referencing the #CustomHelpers function.
what about using the jQuery DataTable plugin. i used it on an MVC2 application i developed.
http://www.datatables.net/
A solution i use to support IE8 (corporate browser, not by choice) was to combine the_lotus's solution with a jquery solution
Since IE8 doesnt support nth-child() use this css
.tableclass tr.even{
background:#E6EDF5;
}
And use jQuery to do this:
$(document).ready(function() {
$(".table tr:nth-child(even)").addClass("even");
});
You could let the framework decide how best to render it, presumably using a bit of browser detection logic and whatever other goodness it has built-in, something like the following, and get on with your life.
:-)
My point being that with this approach the WebGrid will control the alternating grid colors using the best technology it can (best that it is designed to use, at least) for the detected browser. It might not use "nth" CSS syntax, but that might not work for all of your intended audience, anyway, so you'd have to detect the browser and emit different content on your own. Of course everybody should be using a CSS 3.x-compliant browser by now, but mileage varies.
#myWebGrid.GetHtml
(
tableStyle: "some-style",
headerStyle: "some-head-style",
alternatingRowStyle: "some-fancy-alt-row-style",
etc ...
)
The System.Web.Helpers.WebGrid's GetHtml method signature looks like this here:
public IHtmlString GetHtml
(
string tableStyle = null,
string headerStyle = null,
string footerStyle = null,
string rowStyle = null,
string alternatingRowStyle = null,
string selectedRowStyle = null,
string caption = null,
bool displayHeader = true,
bool fillEmptyRows = false,
string emptyRowCellValue = null,
IEnumerable<WebGridColumn> columns = null,
IEnumerable<string> exclusions = null,
WebGridPagerModes mode = WebGridPagerModes.Numeric | WebGridPagerModes.NextPrevious,
string firstText = null,
string previousText = null,
string nextText = null,
string lastText = null,
int numericLinksCount = 5,
object htmlAttributes = null
);
#helper Prop(List prop)
{
foreach (var p in prop)
{
p
}
}
format: #Prop(#item.Prop)