I want to use MvcPaging in a PartialView. I have a search page and I need to paginate the results. So far, only the first page from the results appears - when I am trying to go to page 2 I get in the console a 500 error and nothing happens.
Here are the two actions from controller:
public PartialViewResult SearchResults(string lat, string lng, double? dist)
{
if (Request.IsAjaxRequest())
{
string address = Request["address"];
string latitude = lat;
string longitude = lng;
GeoCoordinate coord = new GeoCoordinate(Double.Parse(latitude, CultureInfo.InvariantCulture), Double.Parse(longitude, CultureInfo.InvariantCulture));
IQueryable<Restaurants> near = (from r in _db.Restaurants select r);
results = new List<Restaurants>();
foreach (Restaurants restaurant in near)
{
double latBD = (double)restaurant.Latitude;
double lngDB = (double)restaurant.Longitude;
if (new GeoCoordinate(latBD, lngDB).GetDistanceTo(coord) <= dist * 1000)
{
results.Add(restaurant);
}
}
return PartialView("_SearchResult", results.ToPagedList(0, 2));
}
return PartialView("Search");
}
public ActionResult PaginationAjax(int? page)
{
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
return PartialView("_SearchResult", results.ToPagedList(currentPageIndex, 2));
}
And the partial view:
#model IPagedList<Restaurants>
#using MvcPaging
foreach (var item in Model)
{
<blockquote>
<h3>#item.Name</h3>
</blockquote>
}
<div class="pager">
#Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalItemCount, new AjaxOptions { UpdateTargetId = "searchResults" }).Options(o => o.Action("PaginationAjax"))
</div>
Does anyone has any idea what I am doing wrong? Thanks!
EDIT:
Error
GET http://localhost/TakeASeat/Restaurants/PaginationAjax?page=2&X-Requested-With=XMLHttpRequest&_=1431698681795 500 (Internal Server Error)
jQuery.ajaxTransport.send # jquery-2.1.3.js:8625
jQuery.extend.ajax # jquery-2.1.3.js:8161
asyncRequest # jquery.unobtrusive-ajax.js:128
(anonymous function) # jquery.unobtrusive-ajax.js:138
jQuery.event.dispatch # jquery-2.1.3.js:4430
jQuery.event.add.elemData.handle # jquery-2.1.3.js:4116
Related
Currently using:
ASP.NET Core 3.1 / EF Core
C#
Code-first approach
Postgres database
I'm building a method to support column searching on a table. I need to feed the column name to be searched by string value and build a query / lambda that can search the right column. I suspect I need to build some sort of expression and search on the expression but am having trouble with the syntax.
Here's the base code:
string search = "Search Value";
string givenColumn = "search_column";
IQueryable<MyModel> data = _dbContext.table;
data = data.Where(data => data.givenColumn.Contains(search));
I'd like to feed the column name in givenColumn and be able to build a query that searches the right column. At first I thought I wanted reflection but I'm looking to build a SQL query based off of a string, so I think I want to build an expression?
TIA!
Here is some sample code for a runtime WhereContains that operates on string columns:
public static class IQueryableExt {
// String.Contains(string)
static MethodInfo containsMI = typeof(string).GetMethod("Contains", 0, new[] { typeof(string) });
// generate r => r.{columnname}.Contains(value)
static Expression<Func<T, bool>> WhereContainsExpr<T>(string columnname, string value) {
// (T r)
var rParm = Expression.Parameter(typeof(T), "r");
// r.{columnname}
var rColExpr = Expression.Property(rParm, columnname);
// r.{columnname}.Contains(value)
var bodyExpr = Expression.Call(rColExpr, containsMI, Expression.Constant(value));
return Expression.Lambda<Func<T,bool>>(bodyExpr, rParm);
}
public static IQueryable<T> WhereContains<T>(this IQueryable<T> src, string columname, string value) => src.Where(WhereContainsExpr<T>(columname, value));
}
Just pass HTML Table id as a parameter onkeyup method of input field. HTML Code:
<input type="text" id="myInput" class="form-control search-input" onkeyup="searchData('myTable')" placeholder="Search...">
Javascript Code for exact match of any column:
function searchData(tableId) {
// Declare variables
var input, filter, table, tr, i, j, column_length, count_td;
column_length = document.getElementById(tableId).rows[0].cells.length;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById(tableId);
tr = table.getElementsByTagName("tr");
if (filter != "") {
for (i = 1; i < tr.length; i++) { // except first(heading) row
count_td = 0;
for (j = 1; j < column_length - 1; j++) { // except first column
td = tr[i].getElementsByTagName("td")[j];
/* ADD columns here that you want you to filter to be used on */
if (td) {
if (td.innerHTML.toUpperCase() === filter) {
count_td++;
}
}
}
if (count_td > 0) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
else {
for (i = 1; i < tr.length; i++) {
tr[i].style.display = "";
}
}
}
I have two action methods in my Controller class:
DetailsAll: to get some data and display in the view
SaveAsPDF: Called on windows.load of DetailsAll.cshtml which should save DetailsAll view as pdf
My issue is in SaveAsPDF Action method. Here I am trying to use Rotativa ActionAsPdf and subsequently BuildFile methods to generate and save the PDF. However, when executing the line "BuildFile", it is not hitting the breakpoint in my DetailsAll Action method, subsequently causing the PDF to be generated blank.
Could you please help where I am going wrong?
[HttpGet]
public ActionResult DetailsAll()
{
var selectionBuilder = builderFactory.GetGeocodeReportSelectionViewModelBuilder();
var companyList = selectionBuilder.Build();
List<GeocodeReportViewModel> viewModel = new List<GeocodeReportViewModel>();
foreach(SelectListItem record in companyList.Companies)
{
var builder = builderFactory.GetGeocodeReportViewModelBuilder(int.Parse(record.Value));
viewModel.Add(builder.Build());
}
var model = new AllGeocodeReportViewModel
{
GeocodeReports = viewModel
};
return View(model);
}
[HttpGet]
public string SaveAsPDF()
{
var report = new ActionAsPdf("DetailsAll")
{
FileName = "OEM_GeocodeReport_" + System.DateTime.Now.ToString("MMYY") + ".pdf",
PageSize = Size.A4,
PageOrientation = Orientation.Landscape,
PageMargins = { Left = 1, Right = 1 }
};
byte[] pdf = report.BuildFile(ControllerContext);
System.IO.File.WriteAllBytes("C:\\" + report.FileName, pdf);
return "true";
}
Finally found the issue after extensive search. I need to send Authentication cookies along with the BuildFile request for this to work. Added the below code and it generates PDF correctly now:
public void SaveAsPDF()
{
var cookies = Request.Cookies.AllKeys.ToDictionary(k => k, k => Request.Cookies[k].Value);
var report = new ActionAsPdf("DetailsAll")
{
FileName = "OEM_GeocodeReport_" + System.DateTime.Now.ToString("MMyy") + ".pdf",
PageSize = Size.A4,
PageOrientation = Orientation.Portrait,
PageMargins = { Left = 3, Right = 3 },
FormsAuthenticationCookieName = System.Web.Security.FormsAuthentication.FormsCookieName,
Cookies = cookies
};
byte[] pdf = report.BuildFile(ControllerContext);
System.IO.File.WriteAllBytes("C:\\" + report.FileName, pdf);
}
Using MVC3, C#, jQuery, Ajax ++
My html
<div>
Start Long Running Process
</div>
<br />
<div id="statusBorder">
<div id="statusFill">
</div>
</div>
The javascript part part of the html
var uniqueId = '<%= Guid.NewGuid().ToString() %>';
$(document).ready(function (event) {
$('#startProcess').click(function () {
$.post("SendToDB/StartLongRunningProcess", { id: uniqueId,
//other parameters to be inserted like textbox
}, function () {
$('#statusBorder').show();
getStatus();
});
event.preventDefault;
});
});
function getStatus() {
var url = 'SendToDB/GetCurrentProgress';
$.get(url, function (data) {
if (data != "100") {
$('#status').html(data);
$('#statusFill').width(data);
window.setTimeout("getStatus()", 100);
}
else {
$('#status').html("Done");
$('#statusBorder').hide();
alert("The Long process has finished");
};
});
}
This is the controller.
//Some global variables. I know it is not "good practice" but it works.
private static int _GlobalSentProgress = 0;
private static int _GlobalUsersSelected = 0;
public void StartLongRunningProcess(string id,
//other parameters
)
{
int percentDone = 0;
int sent = 0;
IEnumerable<BatchListModel> users;
users = new UserService(_userRepository.Session).GetUsers(
//several parameters)
foreach (var c in users)
{
var usr = _userRepository.LoadByID(c.ID);
var message = new DbLog
{
//insert parameters
};
_DbLogRepository.Save(message);
sent++;
double _GlobalSentProgress = (double)sent / (double)_GlobalUsersSelected * 100;
if (percentDone < 100)
{
percentDone = Convert.ToInt32(_GlobalSentProgress);
}
//this is supposed to give the current progress to the "GetStatus" in the javascript
public int GetCurrentProgress()
{
return _GlobalSentProgress;
}
Right now the div with the progress bar never shows up. It is honestly kind of broken. But I hope you understand my logic.
In the loop doing the insertions, I do have this calculation:
double _GlobalSentProgress = (double)sent / (double)_GlobalUsersSelected * 100;
Then I convert the _GlobalSentProgress to a normal int in the
percentDone = Convert.ToInt32(_GlobalSentProgress);
so it no longer has any decimals any longer.
If only I could send this "percentDone" or "_GlobalSentProgress" variable (wich is showing perfectly how many percent I have come in the insertion) asynchronous into the "data" variable in javascript every single time it loops, it would work. Then "data" would do it's "statusFill" all the time and show the bar correctly. This is the logic I use.
I believe the word thrown around in order to accomplish this is "asynchronous". I have looked at 2 very promising guides but I was not able to make it work with my loop.
Anyone have a suggestion on how I can do this?
Edit 2: Outer div is named statusBorder not status.
This is a part of my question which I deleted because its too broad
I created a ActionLink for my blog Archive but I'm having trouble with it because I'm calling multiple items inside it.
This is my codes which return an error message No overload for method ActionLink takes 7 arguments
#model IEnumerable <Project.Models.ArchiveListModel>
#foreach (var item in Model)
{
<br />
#Html.ActionLink(item.AchiveMonth, item.AchiveYear, item.PostCount, "ArchiveBrowse", "Post",
new { AchiveYear = item.AchiveMonth, ArchiveMonth = item.AchiveYear, PostCount = item.PostCount }, null)
}
This is my original codes but doesn't have a link it only gives a list
#foreach (var item in Model)
{
<br />
<li> #System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(item.AchiveMonth) #item.AchiveYear (#item.PostCount) </li>
}
</fieldset><br/>
output:
January 2013 (1)
February 2013 (1)
December 2012 (4)
Here's how I do it in my controller but I know its not working. T_T
public ActionResult Archive()
{
var archivelst = repository.AchiveList().ToList();
return View(archivelst);
}
//this one below is not working
public ActionResult ArchiveBrowse(string archive)
{
var achivemodel = db.Posts.Include("Posts").Single(a => a.Title == archive);
return View(achivemodel);
}
return View(achivemodel);
My ArchiveRepository
public IQueryable<ArchiveListModel> AchiveList()
{
var ac = from Post in db.Posts
group Post by new { Post.DateTime.Year, Post.DateTime.Month }
into dategroup
select new ArchiveListModel()
{
AchiveYear = dategroup.Key.Year,
AchiveMonth = dategroup.Key.Month,
PostCount = dategroup.Count()
};
return ac;
}
What's the correct way to call multiple items in the view?
What I'm trying here is to view the list of Posts under a specific month and year or something like Blog Archives.
Latest Update(working)
Finally I was able to make it work this is now a working one
Updated ArchiveRepository
public IQueryable<ArchiveListModel> AchiveList()
{
var ac = from Post in db.Posts
group Post by new { Post.DateTime.Year, Post.DateTime.Month }
into dategroup
select new ArchiveListModel()
{
AchiveYear = dategroup.Key.Year,
AchiveMonth = dategroup.Key.Month,
PostCount = dategroup.Count()
};
return ac;
}
Updated Controller
public ActionResult ArchiveBrowse(int AchiveYear, int AchiveMonth, int PostCount)
{
var archivemodel = (from a in db.Posts
where a.DateTime.Year == AchiveYear &&
a.DateTime.Month == AchiveMonth
select a).ToList();
return View(archivemodel);
}
Updated View
#foreach (var item in Model)
{
#Html.ActionLink(System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(item.AchiveMonth) + "" + item.AchiveYear + " (" + item.PostCount + ")",
"ArchiveBrowse", "Post", new
{
AchiveYear = item.AchiveYear,
AchiveMonth = item.AchiveMonth,
PostCount = item.PostCount
}, null)
}
It's still not clear to me when you said "call multiple items" so here's my answer, assuming you want to make the list of months years (postcount) into a link. To get this output below
January 2013 (1)
February 2013 (1)
December 2012 (4)
you can concatenate the strings item.AchiveMonth, item.AchiveYear and item.PostCount:
#Html.ActionLink(item.AchiveMonth + " " + item.AchiveYear + " ("+ item.PostCount + ")",
"ArchiveBrowse",
"Post",
new {
AchiveYear = item.AchiveYear,
ArchiveMonth = item.AchiveMonth,
PostCount = item.PostCount },
null)
then in ArchiveBrowse, make sure that your parameters line up properly:
public ActionResult ArchiveBrowse(string AchiveYear, string ArchiveMonth, string PostCount)
{
//Not sure if you want to display posts in the clicked month/year
}
I have a search controller that has a large number of parameters (the search criteria). I want to page through the results using MVCContrib - IPagination. This is all good the problem is how to generate the Link on the Html.Pager. I've tried this in the view
#Html.Pager(Model.Results).Link(p =>
Url.Action("Search", new {
Model.Criteria } ))
but is doesn't work. Do I need to register a route so that the Url.Action understands how to form the link?
Controller code below....
public ViewResult Search(JobSearch search, int? page, IAuthenticatedUser authenticatedUser)
{
// perform search
var query = _jobRepository.CreateQuery<IPagedJobSearch>();
query.SiteId = authenticatedUser.SiteId;
query.JobId = search.Criteria.JobId;
query.Lot = search.Criteria.LotNumber;
query.Street = search.Criteria.StreetInfo.Name;
query.StreetNumber = search.Criteria.StreetInfo.Number;
query.Suburb = search.Criteria.Suburb;
query.Council = search.Criteria.Council;
query.ClientRef = search.Criteria.ClientOrderNumber;
query.ItemsPerPage = 15;
query.PageNumber = page ?? 1;
var pagedResult = query.Execute(); ......
You don't show all of your markup but you'll need to specify each of your parameters like this:
<%= Html.Pager(Model.AssetsPagedList)
.First("First")
.Last("Last")
.Next("Next")
.Previous("Previous")
.Link(currentPage => Url.Action("Browse", new {
page = currentPage,
searchTerm = Model.SearchModel.SearchTerm,
excludedWords = Model.SearchModel.ExcludedWords,
minPrice = Model.SearchModel.MinPrice,
maxPrice = Model.SearchModel.MaxPrice,
locationId = Model.SearchModel.LocationId,
catalogId = Model.SearchModel.CatalogId
}))
%>
Once you have the correct parameters, you'll need to create a controller that accepts each of them:
public ActionResult Browse(int? id, string searchTerm, int? locationId,
GridSortOptions gridSortOptions, int? page, string excludedWords,
decimal? minPrice, decimal? maxPrice, int? catalogId)
{
}