I've got simple action in which I make a request to web service to get a LIST<> of articles for specific group.
Then using pagedList (and specifying the desired page and page number) of course I specify the subset of that list I want to take. The problem is : the article for specific group can be thousand for example - and getting the info for all of them from the web service takes a lot of time and even sometimes crushes (when the articles are above 1000)
Is there a way to get the articles only for the specific page and still to use pagedList because I see that unfortunately we have to call ToPagedList method for the whole collection.
public virtual ActionResult ImportShow(String id, int? menuID, string articlegroupID, string menuforHistory,int? counter,int?page,int? pageSize,string articleDescr, int? ArticleID)
{
List<WebServiceBeaMenu> standartList = ebServiceBea.GetArticle(Convert.ToInt32(menuID), articlegroupID, "", articleDescr);
IPagedList<WebServiceBeaMenu> p_ProductsShow = standartList.ToPagedList(actualpage,actualPageSize);
p_GroupMenu.ProductMenu = p_ProductsShow;
p_GroupMenu.MenuHistory = p_GetMenuHistory.ToList();
p_GroupMenu.MenuLeft = p_GetMenuLeft.ToList();
return PartialView("ImportShow", p_GroupMenu);
}
}
here is my view
#model MvcBeaWeb.GroupMenu
#for (int i = 0; i < Model.ProductMenu.Count; i++)
{
<div>
var item = Model.ProductMenu[i];
#Html.PagedListPager(Model.ProductMenu, page => Url.Action("ImportShow", new { id = Model.LanguageName, menuID = #Session["men"], articlegroupID = Session["article"], articleDescr = Session["articleDescr"], pageSize = Session["pageSize"], page }))
</div>
You should rewrite .GetArticle() Or replace it with whith somethink like .GetPagedArticle() if you have access to WebService. This methid should have all paging params. That's the only way i think.
Your .GetArticle() method should return object like this:
public class Set<T>
{
public Set()
{
Elements = new List<T>();
}
public Set(List<T> elements, int rowsAll)
{
Elements = elements;
RowsAll = rowsAll;
}
public Set(List<T> elements, int rowsOnPage, int pageSelected, int rowsAll)
{
Elements = elements;
PageSelected = pageSelected;
RowsOnPage = rowsOnPage;
RowsAll = rowsAll;
PagesAll = (rowsAll % RowsOnPage == 0) ? rowsAll / RowsOnPage : rowsAll / RowsOnPage + 1; ;
}
public int RowsOnPage { get; set; }
public List<T> Elements { get; set; }
public int? RowsAll { get; set; }
public int PageSelected { get; set; }
public int PagesAll { get; set; }
}
Where Elements should be not all elements, but only paged one.
Related
I am trying to divide listed items into pages by special tags that must be established by custom TagHelper
I have a class to hold data for page and items that will be processed
namespace SportWeb.Models.ViewModels
{
public class PagingInfo
{
public int TotalItems { get; set; }
public int ItemsPerPage { get; set; }
public int CurrentPage { get; set; }
public int TotalPages { get { return (int)Math.Ceiling((decimal)TotalItems / ItemsPerPage); } }
}
}
I am wraping it inside an other modelviewdata
namespace SportWeb.Models.ViewModels
{
public class ProductListViewModel
{
public IEnumerable<Product> Products { get; set; }
public PagingInfo PagingInfos { get; set; }
}
}
Then insert it into Controller Class to retrieve data and establishing logic
public class ProductController : Controller
{
private IProductRepository _iProductRepository;
int PageSize = 4;
public ProductController(IProductRepository iProductRepository)
{
_iProductRepository = iProductRepository;
}
public IActionResult List(int itemPage = 1) => View(new ProductListViewModel
{ Products = _iProductRepository
.List.OrderBy(p => p.ProductID)
.Skip((itemPage - 1) * PageSize)
.Take(PageSize),
PagingInfos = new PagingInfo {
CurrentPage = itemPage,
ItemsPerPage = PageSize,
TotalItems= _iProductRepository.List.Count()} });
}
}
And creating my TagHelper class
namespace SportWeb.InfraSturcture
{
[HtmlTargetElement("div", Attributes = "page-model")]
public class PageLinkTagHelper :TagHelper
{
private IUrlHelperFactory _iUrlHelperFactory;
public PageLinkTagHelper(IUrlHelperFactory iUrlHelperFactory)
{
_iUrlHelperFactory = iUrlHelperFactory;
}
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
public PagingInfo PageModel { get; set; }
public string PageAction { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
IUrlHelper urlHelper = _iUrlHelperFactory.GetUrlHelper(ViewContext);
TagBuilder result = new TagBuilder("div");
for (int i=1; i<PageModel.TotalPages; i++)
{
TagBuilder tag = new TagBuilder("a");
tag.Attributes["href"] = urlHelper.Action(PageAction, new { itempPage = i });
tag.InnerHtml.Append(i.ToString());
result.InnerHtml.AppendHtml(tag);
}
output.Content.AppendHtml(result.InnerHtml);
}
}
}
and here is View page codes
ViewData["Title"] = "List";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#model ProductListViewModel
#addTagHelper SportWeb.InfraStructure.*,SportStore
<h1>List</h1>
#foreach (var p in Model.Products)
{
<div>
<h3>#p.Name</h3>
#p.Description
<h4>#p.Price.ToString("c")</h4>
</div>
}
<div page-model="#Model.PagingInfos" page-action="List"></div>
ViewImport codes below
#using SportWeb.Models
#using SportWeb.Models.ViewModels
#using SportWeb.Entity
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper SportWeb.InfraStructure.*, SportWeb
But when program runs, navigation panel is not appearing on the page
Here navigation panel is not appearing
And When I open page source it seems Tag helper does not work , created tags are not added by the codes.
source page
I do not understand why my tag helper does not work at all. Do you have any idea about where I am making mistake ?
Edit : I am working with CORE 3.0 features. Can it be caused that problem ?
I tried to reproduce your scenario and it worked. I tried with NET Core 2.2 and Visual Studio 2017 15.9.11 and with .NET Core 3.0 Preview 5 with Visual Studio 2019 16.0.3.
Most likely the problem lies on your side. Try to troubleshoot. Start with checking if the tag helper is executed at all. Place a breakpoint in Process() method in your PageLinkTagHelper. See if it is being hit while running the application.
Double check if you are adding the tag helper properly. Properly added tag helper will have Visual Studio IntelliSense, like this:
#addTagHelper *, SportWeb this is answer of problem write it in ViewImport
I have a Model that gets sent to a view. This model has List elements that are used to populate listboxes. In this view, I post to a controller action passing in my model as a parameter. On postback, I can see primitive types, but, can't seem to access the list. Here's my code:
Model:
public class ReportInfoViewModel
{
public int report_id { get; set; } = 0;
public string report_name { get; set; } = "";
public string report_path { get; set; } = "";
public string plaza_param { get; set; } = "y";
public List<FacilityViewModel> facilitieslist { get; set; } = new List<FacilityViewModel>();
}
public class FacilityViewModel
{
public string facility_id { get; set; }
public string facility_name { get; set; }
}
View:
#model CSC.ViewModels.ReportInfoViewModel
#using (Html.BeginForm("ViewReport", "Reports", Model, FormMethod.Post, new { target = "_blank" }))
{
if (#Model.plaza_param.ToString().ToLower().Equals("y"))
{
#Html.DevExpress().ListBox(
l =>
{
l.Name = "lstPlazaParam";
l.Width = Unit.Pixel(300);
l.Height = Unit.Pixel(120);
l.Properties.SelectionMode = ListEditSelectionMode.CheckColumn;
l.Properties.EnableSelectAll = true;
l.Properties.TextField = "facility_name";
l.Properties.ValueField = "facility_id";
l.SelectedIndex = 0;
l.Properties.ValueType = typeof(string);
l.Properties.ValidationSettings.RequiredField.IsRequired = true;
l.Properties.ValidationSettings.RequiredField.ErrorText = "Please select a Plaza";
l.Properties.ValidationSettings.ErrorText = l.Properties.ValidationSettings.RequiredField.ErrorText;
l.Properties.ValidationSettings.ErrorTextPosition = ErrorTextPosition.Bottom;
l.Properties.ValidationSettings.Display = Display.Dynamic;
l.Properties.ValidationSettings.ErrorDisplayMode = ErrorDisplayMode.ImageWithText;
}).BindList(Model.facilitieslist).GetHtml();
ViewContext.Writer.WriteLine("<br />");
}
Controller:
[HttpPost]
[Authorize]
public ActionResult ViewReport(ReportInfoViewModel _model)
{
string _parameterList = "";
ReportViewerViewModel _rptObj = new ReportViewerViewModel();
if (_model.plaza_param.ToLower().Equals("y"))
{
string[] _selected = DevExpress.Web.Mvc.ListBoxExtension.GetSelectedValues<string>("lstPlazaParam");
string subParam = "plazaparam=";
subParam += String.Join(",", _selected);
_parameterList = string.Concat(_parameterList, "#", subParam);
_parameterList = string.Concat(_parameterList, "#usrplazaparam=", getSelectedPlazaDisplayValues(_model.facilitieslist, _selected));**//here, _model.facilitieslist is null**
}
return View("AfterView", _rptObj);
}
What I am trying to do is on post back, send the model back to the controller. All primitive types are sent back, except the list types. How do I send back a list model on post? Any help is appreciated.
I was able to create a hidden field in my view serializing the list and storing it in the hidden field.
#using (Html.BeginForm("ViewReport", "Reports", Model, FormMethod.Post, new { target = "_blank" }))
{
string facilitiesListJson = Newtonsoft.Json.JsonConvert.SerializeObject(#Model.facilitieslist);
#Html.Hidden("FacilitiesList", facilitiesListJson);
//other form objects
}
In my controller action, I deserialized the hidden field(Request.Form) and access the list.
string _jsonString = Request.Form["FacilitiesList"];
List<FacilityViewModel> _objList = JsonConvert.DeserializeObject<List<FacilityViewModel>>(_jsonString);
I am working with MVC5 and I am trying to display 1 image per number in an int, for example:
If the rating is 5, show 5 stars.
I have found a way to do this but it's a real horrible work around, I would prefer to understand how to right the foreach loop on this.
CODE:
public class RestaurantReview
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string Country { get; set; }
public int Rating { get; set; }
}
=========================================================
public ActionResult Index()
{
var model =
from r in _reviews
orderby r.Name descending
select r;
return View(model);
}
=========================================================
Example of Data Source:
static List<OdeToFood.Models.RestaurantReview> _reviews = new List<RestaurantReview>
{
new RestaurantReview {
Id = 1,
Name = "Cinnamon Club",
City = "London",
Country = "UK",
Rating = 10,
},
you do this with CSS really, for example. you html may look like this:
foreach(var item in model.items){
<span id="star#(item.rating)"> </span>
<span>#mitem.name</span>
}
I dont agree with this hard coded solution, but you could do this:
var model =
from r in _reviews
orderby r.Name descending
select new { name = r.name, image = "star" + r.rating, field3 = r.blah, field4 = r.blahblah }
However as explained below, you change the image, you have to change the code, if you change the image location, you also have to change your code. If you want to change the ratings. You have to change our code.
another solution is client side: http://wbotelhos.com/raty
or something similar. https://www.google.co.uk/search?q=jquery+ratings&oq=jquery+ratings&aqs=chrome..69i57j0l5.3043j0j7&sourceid=chrome&espv=210&es_sm=122&ie=UTF-8
A simple for loop would do this:
for (i=0; i < item.Rating; i++) {
<img src="star">
}
For web application in development(ASP.Net MVC), I'm using the telerik grid. The grid is bound to an IQueryable of my list, because it's a big table, and I want that telerik apply it's filter on the list, and then executes this result, not dowloading 10'000 rows(with the joined tables), and then with the filter, use only rows.
I'm using(and I really need it for this page, it's one of the key feature) the filter/order of the grid.
One of the main column(determining the kind of the data) is an enum.
The problem is that I get a "Specified type member is not supported in linq to entities" as soon as I'm trying to filter/sort it.
I've to bind it on the enum(and not the mapped int) because if I use the id, filters/order by will be on an int, and I can't expect that the user knows the id of the foreign table.
I just cannot implement myself again all grids parameter(located in url)(I assume, it's either I do everything, or nothing) and filter it correctly, order it correctly).
Do you have an idea of workaround?
I don't know how your Entity Model looks like but I'll suppose that you've something like this Model:
public partial class Project
{
public int Id { get; set; }
public string Name { get; set; }
public int Status { get; set; }
}
and the Status property represents your enum value then you've this enum:
public enum ProjectStatuses
{
Current = 1,
Started = 2,
Stopped = 3,
Finished = 4,
}
Then just create new ViewModel like this :
public class ProjectDetails
{
public int Id { get; set; }
public string Name { get; set; }
public int Status { get; set; }
public ProjectStatuses StatusValue { get { return (ProjectStatuses) Status; } }
// This property to display in telerik ClientTemplate
public string StatusName { get { return Enum.GetName(typeof (ProjectStatuses), Status ); } }
}
And because I love Extension Methods I'll add this one :
public static class ModelListExtensions
{
public static IQueryable<ProjectDetails> ToViewModelDetails(this IQueryable<Project> modelList)
{
return modelList.Select(m => new ProjectDetails
{
Id = m.Id,
Name = m.Name,
Status = m.Status,
};
}
}
Update :
Here is the Controller
public ActionResult Index()
{
int total;
var viewModel = getGridList(out total);
ViewBag.Total = total;
return View(viewModel);
}
//this Action to get ajax pages
[GridAction(EnableCustomBinding = true)]
public ActionResult ReGetIndex(GridCommand command, int roleId)
{
int total;
var list = getGridList(out total, roleId, command);
return View(new GridModel {Data = list, Total = total});
}
private IEnumerable<ProjectDetails> getGridList(out int total, GridCommand command = null)
{
command = command ?? new GridCommand {Page = 1};
foreach (var descriptor in command.SortDescriptors)
{
if (descriptor.Member == "StatusValue")
descriptor.Member = "Status";
}
foreach (FilterDescriptor descriptor in command.FilterDescriptors)
{
if (descriptor.Member == "StatusValue")
descriptor.Member = "Status";
}
var list = modelService.AllAsQuery()
.ToViewModelDetails() // To convert it to our ViewModel if we have one
.Where(command.FilterDescriptors);
total = list.Count();
return (IEnumerable<ProjectDetails>) list.Sort(command.SortDescriptors)
.Page(command.Page - 1, command.PageSize)
.GroupBy(command.GroupDescriptors).ToIList();
}
And this is the View
#model IEnumerable<ProjectDetails>
#{
Html.Telerik()
.Grid(Model)
.Name("ProjectsGrid")
.Sortable()
.Filterable()
.EnableCustomBinding(true)
.DataBinding(dataBinding => dataBinding
.Ajax()
.Select("ReGetIndex", "Projects"))
.Pageable(page => page.Style(GridPagerStyles.PageSizeDropDown | GridPagerStyles.NextPreviousAndNumeric).Total(ViewBag.Total))
.Columns(column =>
{
column.Bound(m => m.Id).Hidden(true);
column.Bound(m => m.Name);
column.Bound(m => m.StatusValue).ClientTemplate("<#= StatusName #>");
})
.Render();
}
Update :
If you want to enforce at least one sort order you could use something like this:
if (!command.SortDescriptors.Any())
{
command.SortDescriptors.Add(new SortDescriptor {Member = "YourDefaultProperty"});
}
You don't really have choice (or few annoying choices)
Wether you use a class instead of enum (but if you used an enum, that's because it was better).
Or you "pseudo-sort" your enum, and use the mapped int.
public enum TT
{
Brown = 0,
Green = 1
}
Of course, you'll have to check the actual datas (mapped int) in your DB and update them to conform to the new order (can't change enum order without impact). And you'll have to do that everytime you want to insert a value between existing enum values.
Or you wait for next EF / linq / c# version, which should have enum support in linq2entities
I'm using jqGrid to display some data on a page. Within the controller action, we're using an anonymous object to represent the data that the jqGrid needs. My question is, is there a way we can create a strongly typed object to represent the jqGrid data that we are sending with Json()?
Main reason for this is so that we can do unit testing with the objects that are being sent to it.
Thanks!
EDIT:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult GridData(FormCollection form, string alias, string location, string state)
{
int pageSize = Convert.ToInt32(form["rows"]);
int pageIndex = Convert.ToInt32(form["page"]) - 1;
var deviceList = this._device.GetList(CreateFilter(location,alias,state),this._securityCache.GetSecurityContext(),pageSize,pageIndex);
int totalResults = deviceList.TotalRecords;
int totalPages = (int)Math.Ceiling((float)totalResults / (float)pageSize);
var jsonData = new {
total = totalPages,
page = pageIndex + 1,
records = totalResults,
rows = (from device in deviceList.Data
select new {i = device.Alias,cell = new string[]{device.Alias,device.Location,device.RatePlan,device.State,device.DateCreated.ToString()}}).ToArray()
};
return Json(jsonData);
This above here works, but we can't unit test the data that is being passed into the Json() method.
var newJsonData = new JsonJQGridReturnData();
newJsonData.total = totalPages;
newJsonData.page = pageIndex + 1;
newJsonData.records = totalResults;
List<JsonJQGridRow> list = new List<JsonJQGridRow>();
foreach (var device in deviceList.Data)
{
list.Add(new JsonJQGridRow(device.Alias, new string[] { device.Alias, device.Location, device.RatePlan, device.State, device.DateCreated.ToString() }));
}
newJsonData.rows = list.ToArray();
_cookieHelper.SaveCookie("DeviceListIndex", this._securityCache.GetSecurityContext().UserID.ToString(), COOKIE_PAGE_SIZE_KEY, pageSize.ToString());
return Json(newJsonData);
}
Here is my poor attempt at trying to wrap these into strongly typed objects. Unfortunately, running this gives me a "u is undefined" in the jqGrid file. I suspect that this is because the json being passed in is not correctly formatted. Here are the classes....
[DataContract]
public class JsonJQGridReturnData
{
[DataMember]
public int total { get; set; }
[DataMember]
public int page { get; set; }
[DataMember]
public int records { get; set; }
[DataMember]
public JsonJQGridRow[] rows { get; set; }
}
[DataContract]
public class JsonJQGridRow
{
public JsonJQGridRow(string i, string[] columns)
{
this.i = i;
this.cells = columns;
}
[DataMember]
public string i { get; set; }
[DataMember]
public string[] cells { get; set; }
}
If I understand your question you can use Generics to do this:
Model:
// represents one row in the JQGrid
class Customer
{
public string firstname { get; set; }
public string lastname { get; set; }
}
JQGrid class:
class JQGridData<TModel>
{
// add in whatever other properties you want for JQGrid
public int responseTime {get; set; };
public List<TModel> rows = new List<TModel>();
}
Controller Action :
public JsonResult GridData(int page)
{
var gridData = new JQGridData<Customer>();
// Populate your data here, this is just an example:
gridData.rows.Add(new Customer()
{
firstname = "fred", lastname = "pharkas"
});
// return the result
return Json(gridData, JsonRequestBehavior.AllowGet);
}
Result:
{
responseTime: 0
rows: [
{
firstname: "fred"
lastname: "pharkas"
}
]
}
Is that what you were asking?
David,
Here's the kinda thing i use in an app i'm working on at the moment for this type of thing. I know it doesn't provide a strongly typed object as such, but the 'list' could be a part of the model that is then sent ToArray() at the end of the piece.
public JsonResult GridData(int id)
{
// get our messages based on id
var bookingmessagesList = _repository.Find(x => x.ID == id);
var list = new ArrayList();
foreach (var bookingmessage in bookingmessagesList) //populate data containers with read data
{
list.Add(new
{
bookingmessage.ClassRowVersionDate,
bookingmessage.ID,
bookingmessage.BookingID,
bookingmessage.AssignedFrom,
bookingmessage.AssignedTo,
bookingmessage.AssignedDate,
bookingmessage.CompletedDate,
bookingmessage.MessageType,
bookingmessage.Notes
});
}
int totalOjectCount = list.Count;
return Json(new { dataitems = list.ToArray(), totalItems = totalOjectCount });
}
hope it gives you some ideas.. Will be interested to see the suggestions made.
Here's a quick take on a strongly-typed JQGridResult.
public class JQGridResult<T> : JsonResult where T : class
{
public T Model
{
get { return (T)this.Data; }
set { this.Data = value; }
}
}
Used as...
return new JQGridResult<JsonModel> {
Model = new GridModel { ... initialize model here ... }
});
where GridModel is basically a container class holding the strongly typed properties for the grid.
I feel really silly. I had a misspelling in the GridRow that was causing jqGrid to blow up. After I fixed that, I was able to get the jqGrid to work with my strongly typed object...
Now in my unit tests, I can just do...
var result = controllerToTest.GridData(form, null, null, null) as JsonResult;
var data = result.Data as JsonJQGridReturnData;
and now I can access the fields :D