I have just made a perfect paged list in MVC 5.
On each PagedListPager I want to add a CSS class:
#Html.PagedListPager(Model, page => Url.Action("Toetsstart",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
How can I do this?
Adding classes can be done in the PagedListRenderOptions like so:
#Html.PagedListPager(
model,
page => Url.Action("Index",
new
{
page,
sortOrder = ViewBag.CurrentSort,
currentFilter = viewBag.CurrentFilter
}
),
new PagedListRenderOptions()
{
LiElementClasses = new List<string> {"myClass", "yourClass"}
})
There are a number of places you can put classes, including:
LiElementClasses
ClassToApplyToFirstListItemInPager
ClassToApplyToLastListItemInPager
ContainerDivClasses
UlElementClasses
Use this overload of PagedListPager (ref https://github.com/troygoode/PagedList/blob/master/src/PagedList.Mvc/HtmlHelper.cs):
public static MvcHtmlString PagedListPager(this System.Web.Mvc.HtmlHelper html,
IPagedList list,
Func<int, string> generatePageUrl,
PagedListRenderOptions options)
Then use the PagedListRenderOptions to pass in a class name for whatever element you need (ref: https://github.com/TroyGoode/PagedList/blob/master/src/PagedList.Mvc/PagedListRenderOptions.cs)
public PagedListRenderOptions()
{
...
ClassToApplyToFirstListItemInPager = null;
ClassToApplyToLastListItemInPager = null;
ContainerDivClasses = new [] { "pagination-container" };
UlElementClasses = new[] { "pagination" };
LiElementClasses = Enumerable.Empty<string>();
}
If you would like X.PagedList Bootstrap 4 compatible just use:
#Html.PagedListPager((IPagedList)ViewBag.OnePageOfProducts, page => Url.Action("Index", new { page = page }),
new PagedListRenderOptions {
LiElementClasses = new string[] { "page-item" },
PageClasses = new string[] { "page-link" }
})
This way works for me:
#Html.PagedListPager(Model,
page => Url.Action("Index", new { page }),
new PagedListRenderOptions {
DisplayLinkToIndividualPages = true,
DisplayPageCountAndCurrentLocation = false,
MaximumPageNumbersToDisplay = 10,
LiElementClasses = new string[] { "page-item" },
PageClasses = new string[] { "page-link" },
})
And also import on top of the page like this:
#using X.PagedList.Mvc.Core.Common;
Related
I am learning Nopcommerce from the tutorial provided by Pluralsight.
When it comes to adding menu for the plugin in the admin panel it is different with the version 3.5 and 3.8. There is no public SiteMapNode BuildMenuItem()
instead we have to use public void ManageSiteMap(SiteMapNode rootNode).
I have used ManageSiteMap according to the documentation provided by NopCommerce How to add a menu item into the administration area from a plugin, but by using that code i was only able to show the parent menu not the sub menu.
This is my code:
public void ManageSiteMap(SiteMapNode rootNode)
{
var menuItem = new SiteMapNode()
{
Title = "Promo Slider",
ControllerName = "PromoSlider",
ActionName = "CreateUpdatePromoSlider",
Visible = true,
RouteValues = new RouteValueDictionary() { { "area", "admin" } }
};
var createUpdate = new SiteMapNode()
{
SystemName = "Widgets.PromoSlider",
Title = "New Sliders",
ControllerName = "PromoSlider",
ActionName = "CreateUpdatePromoSlider",
Visible = true,
RouteValues = new RouteValueDictionary() { { "area", null } }
};
var manageSlider = new SiteMapNode()
{
SystemName = "Widgets.PromoSlider",
Title = "Manage Sliders",
ControllerName = "PromoSlider",
ActionName = "ManagePromoSliders",
Visible = true,
RouteValues = new RouteValueDictionary() { { "area", null} }
};
menuItem.ChildNodes.Add(createUpdate);
menuItem.ChildNodes.Add(manageSlider);
var pluginNode = rootNode.ChildNodes.FirstOrDefault(x => x.SystemName == "Third party plugins");
if (pluginNode != null)
pluginNode.ChildNodes.Add(menuItem);
else
rootNode.ChildNodes.Add(menuItem);
}
But all it shows is the parent menu only
I want to show like this
Plugins
|---->Promo Slider
|-----------> New Slider
|-----------> Manage Sliders
Can anyone please help me with my code.
Your code need some fixes:
menuItem is a parent node, does not required RouteValues.
Basically, parent node needs SystemName
After doing upper changes, the parent node should be look like:
var menuItem = new SiteMapNode
{
Title = "Promo Slider",
Visible = true,
SystemName = "Widgets.PromoSlider",
};
Okay, now coming to the child nodes, you're creating new node each time..instead of add to the parent one!
var createUpdate = new SiteMapNode()
var manageSlider = new SiteMapNode()
So, change it to:
menuItem.ChildNodes.Add(new SiteMapNode
{
SystemName = "Widgets.PromoSlider",
Title = "New Sliders",
ControllerName = "PromoSlider",
ActionName = "CreateUpdatePromoSlider",
Visible = true,
RouteValues = new RouteValueDictionary() { { "area", null } }
});
menuItem.ChildNodes.Add(new SiteMapNode
{
SystemName = "Widgets.PromoSlider",
Title = "Manage Sliders",
ControllerName = "PromoSlider",
ActionName = "ManagePromoSliders",
Visible = true,
RouteValues = new RouteValueDictionary() { { "area", null } }
});
At the end, add parent node to the Plugins node:
var pluginNode = rootNode.ChildNodes.FirstOrDefault(x => x.SystemName == "Third party plugins");
if (pluginNode != null)
pluginNode.ChildNodes.Add(menuItem);
else
rootNode.ChildNodes.Add(menuItem);
All done! Run it and it will display as you want.
I have a pagination problem. I have a Product model, it has a string ProductCategory attribute. One page can take 4 products, whenever it exceeds 4, it points out page 2. The problem is that when I click "Car" category and click page 2, it takes every product, rather than taking only "Car" .
I got the book from the book, ASP.NET MVC 4, published by apress.
Here is my ProductListViewModel:
public class ProductsListViewModel
{
public List<Product> Products { get; set; }
public PagingInfo PagingInfo { get; set; }
public string CurrentCategory { get; set; }
}
Here is my ProductController's List Action: When I debug the application, at the click at page 2, category parameter is null.
public ViewResult List(string category, int page = 1)
{
ProductsListViewModel model = new ProductsListViewModel
{
Products = repository.Products
.Where(p => category == null || p.ProductCategory.Equals(category))
.OrderBy(p => p.ProductID)
.Skip((page - 1) * PageSize).Take(PageSize).ToList(),
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = category == null ?
repository.Products.Count() :
repository.Products.Where(e => e.ProductCategory == category).Count()
}
};
model.CurrentCategory = category;
return View(model);
}
Here is my List View:
#model SportsStore.WebUI.Models.ProductsListViewModel
#{
ViewBag.Title = "Products";
}
#foreach (var p in Model.Products)
{
<div class="item">
#Html.Partial("ProductSummary", p)
</div>
}
<div class="pager">
#Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x, ProductCategory = Model.CurrentCategory }))
ProductSummary is a partial view that views the product. Pagelinks is a extention methods:
public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pagingInfo,
Func<int, string> pageUrl)
{
StringBuilder result = new StringBuilder();
for (int i = 1; i <= pagingInfo.TotalPages; i++)
{
TagBuilder tag = new TagBuilder("a"); // Construct an <a> tag
tag.MergeAttribute("href", pageUrl(i));
tag.InnerHtml = i.ToString();
if (i == pagingInfo.CurrentPage)
tag.AddCssClass("selected");
result.Append(tag.ToString());
}
return MvcHtmlString.Create(result.ToString());
}
As pictured above, when I click page 2, it gets every product, rather than car. How can I solve it?
Thanks in advance.
NOTE: Routes has been added below:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(null,
"",
new
{
controller = "Product",
action = "List",
category = (string)null,
page = 1
}
);
/*
*http://localhost:56701/?page=2 olmasındansa http://localhost:56701/Page4 olmasını sağlayan kod parçacığı.
*
*/
routes.MapRoute(null,
"Page{page}",
new { controller = "Product", action = "List", category = (string)null },
new { page = #"\d+" }
);
routes.MapRoute(null,
"{category}",
new { controller = "Product", action = "List", page = 1 }
);
routes.MapRoute(null,
"{category}/Page{page}",
new { controller = "Product", action = "List" },
new { page = #"\d+" }
);
routes.MapRoute(null, "{controller}/{action}");
}
}
NOTE 2:
Here is the result when I click page 2 of the Car category:
As you see below, at the page 2, every car items exist. (Blue rectangle). But I do no want to see page 3 and 4 at the bottom of the page (Red rectangle).
Thanks in advance.
The solution has implemented in the book, and it seems it has been escaped from my attention.
Two revisions should be made in the source code, one in List.cshtml :
<div class="pager">
#Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x, category = Model.CurrentCategory }))
Another is in the List action of the ProductController:
public ViewResult List(string category, int page = 1)
{
ProductsListViewModel viewModel = new ProductsListViewModel
{
Products = repository.Products
.Where(p => category == null || p.ProductCategory == category)
.OrderBy(p => p.ProductID)
.Skip((page - 1) * PageSize)
.Take(PageSize).ToList(),
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
**TotalItems = category == null ?
repository.Products.Count() :
repository.Products.Where(e => e.ProductCategory == category).Count()**
},
CurrentCategory = category
};
return View(viewModel);
}
TotalItems attribute shall be updated as mentioned above.
I am using the Kendo MVC wrapper extensions to create a TreeView from my models. I would like to pass some data from the model with HtmlAttributes to the view.
Here is my Action :
public ActionResult Index()
{
var nodeList = new List<TreeViewItemModel>();
nodeList.Add(new TreeViewItemModel
{
Id = "1",
Text = "Item 1",
HasChildren = true,
HtmlAttributes = new Dictionary<string, string>
{
{"class","XXXX"}
},
Items = new List<TreeViewItemModel>
{
new TreeViewItemModel{Id="1.1", Text = "sub Item 1.1",HasChildren = false},
new TreeViewItemModel{Id="1.2", Text = "sub Item 1.2",HasChildren = false}
});
nodeList.Add(new TreeViewItemModel { Id = "2", Text = "Item 2", HasChildren = false });
return View(nodeList);
}
Here is my view :
#using Kendo.Mvc.UI
#model IEnumerable<Kendo.Mvc.UI.TreeViewItemModel>
#(Html.Kendo().TreeView()
.Name("treeView")
.BindTo(Model)
.DragAndDrop(true)
)
Here is the element from Chrome
<li class="k-item k-first" data-id="1" data-uid="6263f4c5-85f3-446c-a843-7d3786fb0f68" role="treeitem" id="treeView_tv_active">
As you can see there isn't any class:XXX in my li Tag So how can I give The XXX class to li Tag?
I can't figure out how to do this automatically, so here's a workaround.
C# passes back a List<Kendo.Mvc.UI.TreeViewItemModel>() to the treeview->datasource->transport->read event:
var items = new List<Kendo.Mvc.UI.TreeViewItemModel>();
////////////////////////////////////////////////////////////////////////////////
// areas of expertise
var aoe = new Kendo.Mvc.UI.TreeViewItemModel()
{
Text = "Areas of Expertise",
Id = "resume-treeview-category-AreasOfExpertise",
HasChildren = false,
HtmlAttributes = new Dictionary<string, string>(){{ "class", "resume-treeview-category"}, {"cat-id", "AreasOfExpertise" }},
};
items.Add(aoe);
return Json(items, JsonRequestBehavior.AllowGet);
I then hook the dataBound event to add the above attributes into the treeview item.
jQuery(document).ready(function ($) {
$("#document-treeview").kendoTreeView({
dataTextField: "Text",
dataSource: {
transport: {
read: {
type: 'POST',
url: "#Url.Action("GetAllTreeData", "Document2")",
contentType: 'application/json; charset=utf-8',
dataType: 'json'
},
parameterMap: function (data, type) {
if (type == "read") {
return JSON.stringify({
id: ResumeId
});
}
}
},
schema: {
model: {
id: "Id",
hasChildren: "HasChildren",
children: "Items"
}
}
},
dataBound: function(e) {
// Apparently reading an item after treeview creation doesn't apply the html attributes. Do that here.
var len = this.dataSource.data().length;
for (var i = 0; i < len; i++)
{
var dataItem = this.dataSource.data()[i];
var uid = dataItem.uid;
var li = $('#document-treeview li[data-uid="' + uid + '"]');
li.addClass(dataItem['HtmlAttributes']['class']);
li.attr('cat-id', dataItem['HtmlAttributes']['cat-id']);
}
}
});
}
Note the HtmlAttributes added from C# are explicitly handled in JavaScript =/
I have a problem with cascading dropdownlists where the second ddl should appear in a partial view and I can't handle it by myself. Please help me to figure out why I have the following bag?
So, I have a view with the first ddl where the user can choose a brand:
#Html.DropDownList("brands", new SelectList(
#ViewBag.Brands, "Id", "BrandName"),
"--select a Brand--",
new
{
id = "ddlBrands",
data_url = Url.Action("ChooseModel", "Home")
})
<div id="divModel"></div>
The ChooseModel method returns the following partial view :
<div id="chooseModel">
<div class="lead">Model</div>
#Html.DropDownList("models", new SelectList(Enumerable.Empty<SelectListItem>
(), "Id", "ModelName"),
"--select a Model--",
new { id = "ddlModels" })
</div>
When a user selects an item in ddlBrands another dropdownlist for models should appear. So, the script looks like this:
$(function () {
$("#ddlBrands").change(function () {
var url = $(this).data('url');
var value = $(this).val();
$('#divModel').load(url, { id: value });
var brandId = $(this).val();
$('#divModel').html("");
$.getJSON("../Home/LoadModels", { brandId: brandId },
function (modelData) {
var select = $("#ddlModels");
select.empty();
select.append($('<option/>', {
value: 0,
text: "-- select a Model --"
}));
$.each(modelData, function (index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
});
});
});
});
And, finally, LooksModels method loading the models for the particular brand:
public JsonResult LoadModels(string brandId)
{
if (string.IsNullOrEmpty(brandId))
return Json(HttpNotFound());
var modelList = unitOfWork.ModelRepository
.GetModelListByBrand(Convert.ToInt32(brandId)).ToList();
var modelData = modelList.Select(m => new SelectListItem()
{
Text = m.ModelName,
Value = m.Id.ToString()
});
return Json(modelData, JsonRequestBehavior.AllowGet);
}
So, when I launch the application and choose a brand in the first ddl, the child models showing fine in second one. Then I choose another brand, and again the right models appeared. But when I choose the brand that I chose first time, I can't choose any models - ddlModels shows me only --select a Model--.
Can you please tell me what error in script (I suppose) I have?
Try this Script :
<script type="text/javascript">
$(document).ready(function () {
$("#ddlBrands").change(function () {
firstDDLValue = $("#ddlBrands").val();
$.post('#Url.Action("LoadModels", "Home")', { fstValue: firstDDLValue }, function (result) {
var select = $("#ddlModels");
select.empty();
select.append($('<option/>', { value: '', text: '--Select--' }));
$.each(result, function (index, Data) {
select.append($('<option/>', {
value: Data.Value,
text: Data.Text
}));
});
});
});
});
</script>
Use This at Controller:
public JsonResult LoadModels(string fstValue)
{
YourClassname obj= new YourClassname ();
int Id = 0;
if (fstValue != "")
Id = Convert.ToInt32(fstValue);
var result = obj.GetModelListByBrand(Convert.ToInt32(Id ));
IList<SelectListItem> Data = new List<SelectListItem>();
for (int i = 0; i < result.Count; i++)
{
Data.Add(new SelectListItem()
{
Text = result[i].Text,
Value = result[i].Value,
});
}
return Json(Data, JsonRequestBehavior.AllowGet);
}
I am using this code in my view:
#(Html.Telerik().TreeView()
.Name("AjaxTreeView")
.BindTo(Model, (item, category) =>
{
// bind initial data - can be omitted if there is none
item.Text = category.Name;
item.Action("Details", "Categories", new { Id = category.Id });
item.Value = category.Id.ToString();
item.LoadOnDemand = category.NOChildren > 0;
})
.DataBinding(dataBinding => dataBinding
.Ajax().Select("_TreeViewAjaxLoading", "Categories")
)
)
It works fine (ajaxified expand and collapse). The action links work fine but only for the root nodes. My current controller that spews out JSON for the ajax load:
[Transaction]
[HttpPost]
public ActionResult _TreeViewAjaxLoading(TreeViewItem node)
{
int? ParentId = !string.IsNullOrEmpty(node.Value) ? (int?)Convert.ToInt32(node.Value) : null;
var nodes = from item in CategoryRepository.GetChildren(ParentId)
select new TreeViewItem
{
Text = item.Name,
Value = item.Id.ToString(),
LoadOnDemand = item.NOChildren > 0
};
return new JsonResult { Data = nodes };
}
does not set the action link. How can I set the action link here? Thanks.
Christian
This seems to do the trick:
[Transaction]
[HttpPost]
public ActionResult _TreeViewAjaxLoading(TreeViewItem node)
{
int? ParentId = !string.IsNullOrEmpty(node.Value) ? (int?)Convert.ToInt32(node.Value) : null;
UrlHelper u = new UrlHelper(this.ControllerContext.RequestContext);
var nodes = from item in CategoryRepository.GetChildren(ParentId)
select new TreeViewItem
{
Text = item.Name,
Value = item.Id.ToString(),
LoadOnDemand = item.NOChildren > 0,
Url = u.Action("Details", "Categories", new { Id = item.Id} )
};
return new JsonResult { Data = nodes };
}