Getting "Sequence contains no elements?" when using paged List - c#

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 .

Related

Department structure treeview passing argument to fetch employees (MVC 4)

I have the following problem: I am making an MVC intranet website for the corporation I'm working for. One part of the job is to make a phonebook - I need a tree like structure of the departments (with depth).
I have a view with two div elements - left (containing the departments, the structure follows below), and a right div which should show all the employees that are working in the selected (clicked) department.
#helper GetTree(List<PhonesClasses.Department> department, int parentID){
foreach(var i in department.Where(a=>a.headDepartmentID.Equals(parentID)))
{
{var childDepartments = department.Where(a => a.headDepartmentID.Equals(i.departmentID)).Count();
if(childDepartments > 0)
{
<li class="haschlid" id="#i.departmentID">
#i.departmentName
<ul class="sub-dep">
#GetTree(department, #i.departmentID)
</ul>
</li>
}
else
{
<li id="#i.departmentID">
#i.departmentName
</li>
}
}
}
The following is the above-mentioned view. As you can see, I had the idea to make a partial view but I'm not sure I'm headed in the right direction.
<div class ="containerStructure">
<div class="leftDivStructure">
#if (Model != null && Model.Count() > 0)
{
<ul class="list" id="deplist">
#Treeview.GetTree(Model, Model.FirstOrDefault().headDepartmentID)
</ul>
}
</div>
<div class="rightDivStructure">
Employee
#*#Html.Partial("_PeopleInDepartment", new {depID = Model.departmentID()})*#
</div>
</div>
My employee and department classes both have DepartmentID fields, so when a department is clicked on in my tree view, a parameter () should be passed to the partial view, or whatever needs to be there to handle the parameter and show the employees. Below is the controller that I think has to fetch the result.
public ActionResult PeopleInDepartment(int depID)
{
List<Person> peopleList = new List<Person>();
peopleList = Persons.GetPersons(depID);
return View(peopleList);
}
For further clarifications please comment!

How display two columns in Mvc WebGrid with single object

I am new to MVC and I want to display name of a user in two columns in a WebGrid as display below.
Currently the web grid display data in below format.
I am binding my WebGrid with List<string>, list contains username.
My Controller
public ActionResult Index()
{
List<string> userList = new List<string>();
userList.Add("User1");
userList.Add("User2");
userList.Add("User3");
userList.Add("User4");
return View(userList);
}
My Cshtml
#using (Html.BeginForm())
{
var grid = new WebGrid(Model);
#grid.GetHtml(columns: grid.Columns(grid.Column(format: (item) => item)));
}
Your desired output is not the right use-case for a webgrid control. Here is the table generation logic for mvc razor view using simple for loop:
#model List<string>
<table >
#{
for (int i = 1; i <= Model.Count; i++)
{
if (i % 2 != 0)
{
#:<tr >
}
<td style="border:solid;">
#Model[i - 1]
</td>
if (i % 2 == 0)
{
#:</tr>
}
}
}
</table>
I've added a css style style="border:solid;" just to show border of all the table cells. You can customize it as per your needs.
This code creates below table:

ASP.Net MVC 4 Razor - Paging through search results on webgrid

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."

ASP.NET MVC CheckBoxList from model with List Property

Apologies if the title is unclear.
I'm trying to return my model from a form submit in ASP.NET MVC.
My question is nearly the same as this question, only differing in that I don't have a List<Model> but a model like:
public Model
{
string UserName {get; set;}
string Password {get; set;}
List<Roles> UserRoles {get; set;}
}
where I need the UserRoles as checkboxes that the admin can select from when creating a new user. My question is, I'm unsure how to use a '#Html.CheckBoxFor' against a list. I tried this:
#for (var i = 0; i < Model.UserRoles.Count();i++ )
{
#Html.HiddenFor(model => model.UserRoles[i].RoleID)
#Html.CheckBoxFor(model => model.UserRoles[i].Selected)
#Html.LabelFor(model => model.UserRoles[i].Name)
}
which in no way worked - every label on the page is "Name", and my List was empty in the POST. Can anyone offer me any guidance on this?
No need to go away from Razor at all.
This works for me:
for (var i = 0; i < Model.UserRoles.Count(); i++)
{
var role = Model.UserRoles[i];
#Html.HiddenFor(model => model.UserRoles[i].RoleId)
#Html.CheckBoxFor(model => model.UserRoles[i].Selected)
#Html.LabelFor(model=> model.UserRoles[i].Name, role.Name)
}
See below code, this way you don't need to hide the role Id, also when you save the selected roles for the user, you don't need to loop through all roles to see which role is selected.
View
#foreach (Roles info in Model.UserRoles)
{
<span>
<input type="checkbox" class="checkbox" name="selectedRoles" value="#info.RoleName" id="#infoRoleName" />
<label for="#info.RoleName">#info.RoleName</label>
</span>
}
Action
[HttpPost]
public ActionResult CreateUsers(Model model, string[] selectedRoles)
{
//
}
From your code in the view, the post should work fine providing your post action looks like this:
[HttpPost]
public ActionResult Action(Model model)
{
return View(model);
}
i.e. passing your model across as the argument.
Also make sure you have your model reference in the view too:
#model YourNameSpace.Model
Post a list of check boxes to server and get list of checked items
linq left join to check whether checked, generating checkboxes,received checked list
View
List<eDurar.Models.tbl_ISOCetificate> ModList = db.tbl_ISOCetificate.ToList();
var li = (from cert in db.tbl_ISOCetificate join comCert in db.tbl_CompCertificate on cert.Cert_id equals comCert.CompCer_id into jo from b in jo.DefaultIfEmpty()
select new {cert.Cert_id,cert.Cert_Name,chkd = b.CompCer_SerId==null?"":"checked"}).ToList();
foreach (var item in li)
{
#:<div style="width: 30%; display: inline-block; margin: 1em">
#:<input type="checkbox" #item.chkd name="CheckedCertificates" value="#item.Cert_id">
#:<label>#item.Cert_Name</label>
#:</div>
}
Controller
[HttpPost]
public ActionResult ManageSurveyGroup(int[] CheckedCertificates)
{
return View();
}

dropdown in mvc3 edit form

This maybe very simple but I cant seem to sort it out on my own.
I have created a simple db and entity modal that looks like this
I am trying to create an Create form that allows me to add a new Order. I have a total of 3 tables so what I am trying to do is have the form allowing the person to enter Order date and also has a dropdown list that allows me to select a product from the product table
I want to be able to create a Add or Edit view that allow me to insert the OrderDate into the OrderTable and also insert the OrderID and selected ProductID into OrderProduct.
What steps do I need to do here.
I have created an OrderController and ticked the "Add Actions" and than added a Create View which looks like this
#model Test.OrderProduct
#{
ViewBag.Title = "Create2";
}
<h2>Create2</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>OrderProduct</legend>
<div class="editor-label">
#Html.LabelFor(model => model.OrderID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OrderID)
#Html.ValidationMessageFor(model => model.OrderID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ProductID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ProductID)
#Html.ValidationMessageFor(model => model.ProductID)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
This creates the view that contains a textbox for both OrderID and ProductID however no date.
My controller CreatePost hasnt been changed
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
var data = collection;
// TODO: Add insert logic here
// db.Orders.AddObject(collection);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
My questions are,
1.How do I swap out ProductID textbox to be a dropdown which is populated from Product
2.How do I get the data from FormCollection collection? I thought of just a foreach however I dont know how to get the strongly typed name
Any help for a newbie would be very helpful.
Thank you!
First thing's first, don't bind to the Order entity. Never bind to an EF object, always try and use a ViewModel. Makes life simpler for the View, and that is the goal here.
So, have a ViewModel like this:
public class CreateOrderViewModel
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public int SelectedProductId { get; set; }
public IEnumerable<SelectListItem> Products { get; set; }
}
That's it right now.
Return that to your View in your [HttpGet] controller action:
[HttpGet]
public ActionResult Create()
{
var model = new CreateOrderViewModel
{
Products = db.Products
.ToList() // this will fire a query, basically SELECT * FROM Products
.Select(x => new SelectListItem
{
Text = x.ProductName,
Value = x.ProductId
});
};
return View(model);
}
Then to render out the list of Products: (basic HTML excluded)
#model WebApplication.Models.CreateOrderViewModel
#Html.DropDownListFor(model => model.SelectedProductId, Model.Products)
The only thing i don't know how to do is bind to the DateTime field. I'm guessing you would need an extension method (HTML Helper) which renders out a Date Picker or something. For this View (creating a new order), just default to DateTime.Now.
Now, onto the [HttpPost] controller action:
[HttpPost]
public ActionResult Create(CreateOrderViewModel model)
{
try
{
// TODO: this manual stitching should be replaced with AutoMapper
var newOrder = new Order
{
OrderDate = DateTime.Now,
OrderProduct = new OrderProduct
{
ProductId = SelectedProductId
}
};
db.Orders.AddObject(newOrder);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Now, i also think your EF model needs work.
To me (in English terms), a Product can have many orders, and an Order can have many Products.
So, it should be a many-to-many. Currently it's a 1-1 with a redundant join table. Did you generate that from a DB? If so, your DB possibly needs work.
You should have a navigational property called Products on the Order entity, which references a collection of Product, made possible by a silent join to the join table in the many-to-many.
This also means you no longer have a DropDownList, but a MultiSelectDropDownList.
Thanks Craig. Your few days (as at time of posting) of MVC have solved my few days of trying to get the selected value back from DropDownListFor.
I had no problem in the Create view in getting the selected value of the DDLF, but the Edit view was a completely different matter - nothing I tried would get the selected value back in the Post. I noticed the selected value was lurking in the AttemptedValue of the ModelState, and so Dr.Google referred me here.
I had this in my view
#Html.DropDownList(model => model.ContentKeyID, Model.ContentKeys, Model.ContentKeyName)
where ContentKeys is a SelectList populated from the DB via a ViewModel, and ContentKeyName is the curently selected name.
The wierd thing is, I have another DDL on the view populated in an identical manner. This one works. Why, I don't know. It is the second DDL on the form, but I can't see that making a difference.
I read somewhere else it might have been that I was using Guids as the Id, but that didn't seem to make a difference - I changed to Int32, but don't think I had to - I think it's enums that disagree with DDLF. Nullables seemd to make no difference either.
Now that I've added the form collection to my Post ActionResult, and get the selected value using
-view
#Html.DropDownList("ContentKey", Model.ContentKeys)
-in controller (Post)
contentKeyId = int.Parse(form.GetValue("ContentKey").AttemptedValue);
all is good, and I can get on with more exciting things. Why is that the simplest things can hold you up for so long?
I have been struggling with this over the last day or so too. I'll share my limited knowledge in the hope that it will help someone else.
Note that I use a singleton with a pre-populated list to keep my example application small (i.e. no EF or DB interaction).
To show the ProductList you will need to have a ViewBag or ViewData item which contains the ProductList.
You can set this up in the Controller with something like
ViewData["ProductList"] = new SelectList(Models.MVCProduct.Instance.ProductList, "Id", "Name", 1);
Then update your View to something like:
<div class="editor-field">#Html.DropDownList("ProductList")</div>
For the Post/Create/Update step you need to look into the FormCollection to get your results. Reading other posts it sounds like there used to be a bug in here, but it's fixed now so ensure you have the latest. For my example I have a DropDownList for Product so I just get the selected Id and then go searching for that Product in my list.
[HttpPost]
public ActionResult Create(FormCollection form )//Models.MVCOrder newOrder)
{
MVC.Models.MVCOrder ord = Models.MVCOrder.Instance.CreateBlankOrder();
//Update order with simple types (e.g. Quantity)
if (TryUpdateModel<MVC.Models.MVCOrder>(ord, form.ToValueProvider()))
{
ord.Product = Models.MVCProduct.Instance.ProductList.Find(p => p.Id == int.Parse(form.GetValue("ProductList").AttemptedValue));
ord.Attribute = Models.MVCAttribute.Instance.AttributeList.Find(a => a.Id == int.Parse(form.GetValue("attributeId").AttemptedValue));
UpdateModel(ord);
return RedirectToAction("Index");
}
else
{
return View(ord);
}
}
I've only been working on MVC3 for the last few days, so any advice on improving the above would be appreciated.

Categories

Resources