Umbraco pagination - c#

First time Umbraco user.
I'm looking to add pagination to the following basic loop:
#foreach (var example in CurrentPage.Children.OrderBy("createDate descending").Take(8)){
//Do Stuff//
}
Any ideas? Thanks

After a good amount of work and research, here is my final code for pagination in umbraco. Replace the examples with your stuff, and pageSize is the amount of posts shown on each page.
#{
var pageSize = 8;
if(Model.Content.HasValue("numberOfItemsPerPage")){
pageSize = Model.Content.GetPropertyValue<int>("numberOfItemsPerPage");}
var page = 1; int.TryParse(Request.QueryString["page"], out page);
var items = Umbraco.TypedContent(Model.Content.Id).Children.Where(x => x.DocumentTypeAlias == "exampleAlias" && x.IsVisible());
var totalPages = (int)Math.Ceiling((double)items.Count() / (double)pageSize);
if (page > totalPages)
{
page = totalPages;
}
else if (page < 1)
{
page = 1;
}
foreach (var item in items.Skip((page - 1) * pageSize).Take(pageSize).OrderBy("createDate descending"))
{
<div class="example-div">
<h2>#item.GetPropertyValue("example")</h2>
</div>
}
if (totalPages > 1)
{
<div class="pagination">
<ul>
#if (page > 1)
{
<li>Prev</li>
}
#for (int p = 1; p < totalPages + 1; p++)
{
<li class="#(p == page ? "active" : string.Empty)">
#p
</li>
}
#if (page < totalPages)
{
<li>Next</li>
}
</ul>
</div>
}
}
Hope this stops a headache for someone.

Phil's answer is great, but I would recommend putting the order on the items variable rather than the foreach - that way if any more complicated sorting is necessary it's being done before the pagination is implemented.
The updated code snippets would be:
#{
var pageSize = 8;
if(Model.Content.HasValue("numberOfItemsPerPage")){
pageSize = Model.Content.GetPropertyValue<int>("numberOfItemsPerPage");}
var page = 1; int.TryParse(Request.QueryString["page"], out page);
var items = Umbraco.TypedContent(Model.Content.Id).Children.Where(x => x.DocumentTypeAlias == "exampleAlias" && x.IsVisible()).OrderByDescending(x => x.CreateDate);
var totalPages = (int)Math.Ceiling((double)items.Count() / (double)pageSize);
if (page > totalPages)
{
page = totalPages;
}
else if (page < 1)
{
page = 1;
}
foreach (var item in items.Skip((page - 1) * pageSize).Take(pageSize)
{
<div class="example-div">
<h2>#item.GetPropertyValue("example")</h2>
</div>
}
if (totalPages > 1)
{
<div class="pagination">
<ul>
#if (page > 1)
{
<li>Prev</li>
}
#for (int p = 1; p < totalPages + 1; p++)
{
<li class="#(p == page ? "active" : string.Empty)">
#p
</li>
}
#if (page < totalPages)
{
<li>Next</li>
}
</ul>
</div>
}
}

My 50 cents
Jeroen Breuer created a github project called Hybrid Framework in which he has added some route hijacking to an umbraco side to do paging and have strongly typed models. Take a look at it and i'm sure you will like it. It also uses caching i believe.
There was also a video about this i saw but i could not find it anymore.
Hope this helps people trying to implement Paging and some other nice stuff to you Umbraco projects.
UPDATE: found the video on GitHub in readme

These are all great answers, especially the pointer to Jeroen Breuer's library, but just in the name of being thorough and talking about all options -- if you are using jquery in your project and if you have relatively small result sets you could also go with a simple front end only solution.
You'd just bind the entire results list and then use a library like JPList (http://jplist.com ) as I have done here. Go to http://www.charterpublic.org/find-a-school/ and type in city Denver for example. You'll see there are 50+ results. I bind the entire results list then use jplist to make it sortable/pageable etc.
#if (results.Any())
{
<div class="list">
#foreach (var result in results.OrderByDescending(r => r.Name))
{
<div class="list-item">
//build your item
</div>
}
</div>
}
<div class="jplist-panel">
<!-- bootstrap pagination control -->
<ul class="pagination text-center jplist-pagination"
data-control-type="boot-pagination"
data-control-name="paging"
data-control-action="paging"
data-range="4"
data-mode="google-like"></ul>
<!-- items per page dropdown -->
<div class="hidden dropdown pull-left jplist-items-per-page"
data-control-type="boot-items-per-page-dropdown"
data-control-name="paging"
data-control-action="paging">
<button class="btn btn-primary dropdown-toggle"
type="button"
data-toggle="dropdown"
id="dropdown-menu-1"
aria-expanded="true">
<span data-type="selected-text">Items per Page</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdown-menu-1">
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#" data-number="3">3 per page</a>
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#" data-number="5">5 per page</a>
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#" data-number="10" data-default="true">10 per page</a>
</li>
<li role="presentation" class="divider"></li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#" data-number="all">View All</a>
</li>
</ul>
</div>
</div>
Then at the bottom of your view...
<script type="text/javascript">
$(document).ready(function () {
$('#demo').jplist({
itemsBox: '.list',
itemPath: '.list-item',
panelPath: '.jplist-panel'
});
});
</script>
There are other front end libraries that do this, but I found JPList the easiest to use for me.
The downside is it's not lazy loaded so it's a little heavier, but with smallish lists like mine here this was a great and simple solution.

I know that this is old , I used the Phil code recomendations and works very good.
But all the pages when incresing the pagination buttons works as infinite regeneration, what I mean is how can I do this as example:
Prev 123456789...Next and when is selected the page 5 for example shows like this:
Prev 5 6 7 8 9 10 11 12 13 ... Next and in the inverse or last page like this:
Prev ... 47 48 49 50 51 52 53 54 55
What I mean guys is to have just a 9 pages on click in the pagination buttons, but I need to implement with the same code that Phil Share :
#{
var pageSize = 8;
if(Model.Content.HasValue("numberOfItemsPerPage")){
pageSize = Model.Content.GetPropertyValue<int>("numberOfItemsPerPage");}
var page = 1; int.TryParse(Request.QueryString["page"], out page);
var items = Umbraco.TypedContent(Model.Content.Id).Children.Where(x => x.DocumentTypeAlias == "exampleAlias" && x.IsVisible());
var totalPages = (int)Math.Ceiling((double)items.Count() / (double)pageSize);
if (page > totalPages)
{
page = totalPages;
}
else if (page < 1)
{
page = 1;
}
foreach (var item in items.Skip((page - 1) * pageSize).Take(pageSize).OrderBy("createDate descending"))
{
<div class="example-div">
<h2>#item.GetPropertyValue("example")</h2>
</div>
}
if (totalPages > 1)
{
<div class="pagination">
<ul>
#if (page > 1)
{
<li>Prev</li>
}
#for (int p = 1; p < totalPages + 1; p++)
{
<li class="#(p == page ? "active" : string.Empty)">
#p
</li>
}
#if (page < totalPages)
{
<li>Next</li>
}
</ul>
</div>
}
}
Just to have a limit of 9 pages with the (...) according the page position.
Help!

Related

Make .NET Core app reload experience like angular/react

I have a website build with .net core technology.
there are menu on left side, and display content on right side.
but currently, when I click to menu, it reload entire page and load all menu again and then load content of page.
what I want is, when click on menu, it should load content for that menu without reloading page.
below code I tried, but I think that causes issue, because I used global variable in JavaScript in every page, so when I click on any menu that will call my below function and load content, but when I click on another menu it load another page, but first page global variable are still access on second page.
async function getPage(url) {
let response = await fetch(url);
let data = await response.text();
return data;
}
function loadPage(url) {
$("#main-layout-container").html("<div class='div-loader'></div>");
getPage(url).then((data) => {
$("#main-layout-container").html(data);
});
}
If you use JavaScript, I wrote a simple demo:
View:
<div class="all">
<div class="menu">
<ul class="first">
<li>
First-level directory-1
<ul class="sec">
<li>1-1</li>
</ul>
<div class="content">1-1:content</div>
</li>
<li>
First-level directory-2
<ul class="sec">
<li>2-1</li>
<li>2-2</li>
</ul>
<div class="content">2-1:content</div>
<div class="content">2-2:content
</div>
</li>
<li>
First-level directory-3
<ul class="sec">
<li>3-1</li>
<li>3-2</li>
<li>3-3</li>
</ul>
<div class="content">3-1:content</div>
<div class="content">3-2:content</div>
<div class="content">3-3:content</div>
</li>
<li>
First-level directory-4
<ul class="sec">
<li>4-1</li>
<li>4-2</li>
<li>4-3</li>
<li>4-4</li>
</ul>
<div class="content">4-1:content</div>
<div class="content">4-2:content</div>
<div class="content">4-3:content</div>
<div class="content">4-4:content</div>
</li>
</ul>
</div>
<div class="clear"></div>
</div>
#section Scripts{
<script src="~/jquery/jquery.js"></script>
<link href="~/css/test.css" rel="stylesheet" />
<script>
var firstList = $('.first > li'); // Grab the first level menu li
var secList = $('.sec'); // Grab the ul of the secondary menu for easy operation
secList.hide();
for (var i = 0; i < secList.length; i++) {
firstList.eq(i).children('.content').hide();
}
firstList.eq(0).children('.content').eq(0).show(); //The content below 1.1 is displayed by default
var ind = 0; // Define variables to store the subscript of the first-level menu when clicked
// Click event of the first level menu
firstList.click(function () {
ind = $(this).index();
if (secList.eq(ind).hasClass('show')) {
for (var j = 0; j < secList.length; j++) {
secList.eq(j).hide();
}
secList.eq(ind).removeClass('show');
} else {
for (var k = 0; k < secList.length; k++) {
secList.eq(k).hide().removeClass('show');
}
secList.eq(ind).show();
secList.eq(ind).addClass('show');
}
});
// Click event of secondary menu
$('.sec > li').click(function (event) {
var sec = $(this).index();
for (var i = 0; i < secList.length; i++) {
firstList.eq(i).children('.content').hide();
}
firstList.eq(ind).children('.content').eq(sec).show();
event.stopPropagation(); // Prevent events from bubbling up
});
</script>
}
Demonstration effect:

How can I create a row for every 3rd column in Razor mvc5?

I am currently trying to add a new row for each 3rd column with razor. However, with the current code, only the first three columns get wrapped in a row, and the rest get skipped. I have been looking around for a fix, but none of it seems to work with my code. Does anyone have a solution for this?
#model IEnumerable<Byporten.createpost>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_LayoutClient.cshtml";
}
<div class="container">
#{
var itemCount = 0;
}
#while (itemCount < 3)
{
foreach (var item in Model.Reverse().Take(9))
{
if(itemCount == 0 )
{
#:<div class="row">
}
<div class="col-lg-4 col-md-6 col-sm-6">
<div class="image-section">
<img src="~/images/uploads/#Html.DisplayFor(modelItem => item.ImageURL)"/>
</div>
<div class="title-section">
<h5><span class="fa fa-pencil"></span> #Html.DisplayFor(modelItem => item.Title)</h5>
#Html.ActionLink("Les mer", "viewArticle", new { id = item.Id })
</div>
</div>
itemCount++;
if ((itemCount % 3) == 0)
{
#:</div>
}
}
}
#{itemCount = 0;}
</div>
None of these worked for me, but the following did:
#foreach (var item in Model.Items)
{
var itemCount = 0;
foreach (var listItem in ((ListViewModel)item).ListItemViewModel.Items)
{
if (itemCount == 0)
{
#:<div class="row">
}
<div class="col-md-4">
<span class="organogram-outter-ring"></span>#listItem.Fields.Title
<div style="display:none;" class="sf-list-content">
#Html.Raw(listItem.Fields.Content)
</div>
<div class="organogram-outter-ring"></div>
</div>
if (itemCount == 2)
{
itemCount = 0;
#:</div>
}
else
{
itemCount++;
}
}
}
It's going to result in invalid markup because itemCount == 0 will be true only once. Replace if (itemCount == 0) with if (itemCount % 3 == 0 || itemCount % 3 == 3).
I would also get rid of the while loop and the itemCount reset at the bottom.
Use Html.Raw() method to avoid compilation problems with conditional closing tag, and temp variable insertRow to avoid repeating in row condition:
<div class="container">
#{
var itemCount = 0;
}
#{
foreach (var item in Model.Reverse().Take(9))
{
var insertRow = itemCount % 3 == 0;
if(insertRow)
{
#Html.Raw("<div class="row">")
}
<div class="col-lg-4 col-md-6 col-sm-6">
<div class="image-section">
<img src="~/images/uploads/#Html.DisplayFor(modelItem => item.ImageURL)"/>
</div>
<div class="title-section">
<h5><span class="fa fa-pencil"></span> #Html.DisplayFor(modelItem => item.Title)</h5>
#Html.ActionLink("Les mer", "viewArticle", new { id = item.Id })
</div>
</div>
if (insertRow)
{
#Html.Raw("</div>")
}
itemCount++;
}
}
</div>
And also while (itemCount < 3) loop is look strange and unnecessary for your task.
So, I know I am a little late to the game and there is an accepted answer, however, I want to add my rendition because it requires no duplicate if statements and no code compilation squigglies.
My approach uses an inner for loop based on the number of columns you want to have before creating a new row:
<table>
<thead>
<tr>
<td><b>My List Data:</b></td>
</tr>
</thead>
<tbody>
#{
var items = Model.MyList;
const int colCount = 2;
}
#for (var i = 0; i < items.Count(); i += colCount)
{
<tr>
#for (var c = 0; c < colCount && i + c < items.Count(); c++)
{
<td>#(items[i + c].Display):</td>
}
</tr>
}
</tbody>
</table>
The premise is to determine what your column count is, that is show above using const int colCount =2;
Then, loop, using a for loop, on your list but instead of incrementing by 1, as is traditional, increment by your colCount value.
Then, have your row tag. This means a row will be created every n+colCount items.
Within that row tag, have another for loop that increments by 1 until you either reach your colCount OR your parent iterator plus your colCount iterator equals or exceeds the total items in your list.
Within that for loop, simply create a cell that is at the index of i (outer iterator) + c (colCount) iterator.
This gives you a nice left to right, top to bottom table structure from a flat list without extra if statements and compilation warnings.

Filling Data For Partial View MVC

We're developing news website we're confused with some concept of usage. I'd like to ask and know better if possible. We've a homepage which may contain a lot of models at once so we're separating our homepage to partial views and we're planning to feed them with the appropriate models.
In one partial we're enumerating in categories that are not marked as deleted and we've two types of categories. One of them displays the latest post and the other displays 4 posts at once. We've achieved this actually but as i've mentioned we would like to know if there is a better way or if we're doing anything wrong because right now we're keeping the connection to the context open until the partial is rendered.
Here is the code for views
Partial View Code (CategoryRepeater.cshtml)
#using SosyalGundem.WebUI.DatabaseContext;
#{
var categoryList = new List<PostCategories>();
var db = new SosyalGundemDb();
categoryList = db.PostCategories.Include("Posts").Where(x => !x.IsDeleted).ToList();
}
#for (int i = 0; i < categoryList.Count; i++)
{
if (i % 3 == 0 || i == 0)
{
#Html.Raw("<div class=\"row-fluid spacer\">")
}
var category = categoryList[i];
if (category.PostCategoryType == 1)
{
<div class="span4">
<h3 class="title"><span>#category.PostCategoryName</span></h3>
#{
var article = category.Posts.FirstOrDefault();
if (article != null)
{
<article class="post">
<div class="entry clearfix">
<div class="span6">
<a href="#" title="Permalink to Suspen disse auctor dapibus neque pulvinar urna leo" rel="bookmark">
<img width="225" height="136" src="#Url.Content("~/Content/uploadedimages/" + article.Media.ToList()[0].MediaContent )" alt="shutterstock_70184773" />
</a>
</div>
<div class="span6">
<h4 class="smallnewstitle">#article.PostTitle</h4>
<p>#(article.PostSummary.Length > 100 ? article.PostSummary.Substring(0, 100) : article.PostSummary)</p>
<div class="meta">
<span class="date">#article.PostDate.ToString("MMMM dd, yyyy")</span>
</div>
</div>
</div>
</article>
}
}
</div>
}
else
{
<div class="video-box widget span4">
<h3 class="title"><span>#category.PostCategoryName</span></h3>
#{
int cati = 0;
var firstPost = category.Posts.OrderByDescending(x => x.PostDate).FirstOrDefault();
}
#if (firstPost != null)
{
<h4 class="smallnewstitle">#firstPost.PostTitle</h4>
<p>#(firstPost.PostSummary.Length > 100 ? firstPost.PostSummary.Substring(0, 100) : firstPost.PostSummary) </p>
<ul>
#foreach (var item in category.Posts.OrderByDescending(x => x.PostDate))
{
if (cati <= 3)
{
<li>
<a href="#" title="#item.PostTitle" rel="bookmark">
<img width="225" height="136" src="#Url.Content("~/Content/images/dummy/shutterstock_134257640-225x136.jpg")" alt="shutterstock_134257640" />
</a>
</li>
}
else
{
break;
}
cati++;
}
</ul>
}
</div>
}
if (i % 3 == 0 && i != 0)
{
#Html.Raw("</div>")
}
}
#{
db.Dispose();
}
Separate your concerns. You can see this project for start: http://www.codeproject.com/Tips/617361/Partial-View-in-ASP-NET-MVC
Controller
#using SosyalGundem.WebUI.DatabaseContext;
public ActionResult SomeAction()
{
var model = new CategoriesModel
{
NotDeletedCategories = db.PostCategories.Include("Posts").Where(x => !x.IsDeleted).ToList(),
DeletedCategories = db.PostCategories.Include("Posts").Where(x => x.IsDeleted).ToList()
};
return View(model);
}
Model
public class CategoriesModel
{
public List<PostCategories> NotDeletedCategories {get;set;}
public List<PostCategories> DeletedCategories {get;set;}
};
View
#model CategoriesModel
#Html.RenderPartial("DeletedCategories", Model.DeletedCategories)
#Html.RenderPartial("NotDeletedCategories", Model.NotDeletedCategories)
Hi Jinava,
I would suggest bind Model to the View,
Like,
public ActionResult CategoryRepeater()
{
var multiViewModel = new MultiViewModelModel
{
ModelForParialView1= new XYZ(),
ModelForParialView2= new PQR()
};
return View(model);
}
For the View
#model MultiViewModelModel
And then PAss the views with the MultiViewModelModel.ModelForParialView1 and MultiViewModelModel.ModelForParialView2
You can perform all the model operations on the view.
And at the controller level perform all the database operations and release the database connection there itself no need to get that on the view.
Hope this explanation helps you.

Recursively create accordion html from list of links in C#

I am scraping a remote page for links, which I have in a List. I am trying to get the list printed out as necessary for a jquery accordion. I have the html no problem, but my loops are off a bit and aren't nesting properly.
Here is an example of the List:
Heading 1
link1
link2
link3
Heading 2
link4
link5
link6
So here is how I need to get the html formatted:
<div data-role="collapsible" data-collapsed="true">
<h3>Heading 1</h3>
<p>
<ul>
<li>link1</li>
<li>link2</li>
<li>link3</li>
</ul>
</p>
</div>
<div data-role="collapsible" data-collapsed="true">
<h3>Heading 2</h3>
<p>
<ul>
<li>link4</li>
<li>link5</li>
<li>link6</li>
</ul>
</p>
</div>
And here is the code I have so far, it should be mentioned I am using the HTMLAgilityPack:
HtmlNodeCollection OneHome = document.DocumentNode.SelectNodes("//div[#id='accordion1']");
var OneHomelinks = OneHome.Descendants("a")
.Select(a => a.OuterHtml)
.ToList();
foreach (string link in OneHomelinks)
{
if (link.Contains('#'))
{
Response.Write("<div data-role=\"collapsible\" data-collapsed=\"true\">");
Response.Write("<h3>" + link + "</h3>");
Response.Write("<p>");
Response.Write("<ul>");
}
if (!link.Contains('#'))
{
Response.Write("<li>" + link + "</li>");
} else {
Response.Write("</ul>");
Response.Write("</p>");
Response.Write("</div>");
}
}
Basically I am trying to pull out the Headings by using the '#' in the href, and resetting the at that point - but something is off, the lists aren't being properly formed. Any help is super appreciated here!
CURRENT OUTPUT
<div data-role="collapsible" data-collapsed="true">
<h3>Heading 1</h3>
<p></p>
<ul></ul>
<p></p>
</div>
<li><a href="link1.html>link1</a></li>
<li><a href="link2.html>link2</a></li>
<li><a href="link3.html>link3</a></li>
<div data-role="collapsible" data-collapsed="true">
<h3>Heading 2</h3>
<p></p>
<ul></ul>
<p></p>
</div>
<li><a href="link4.html>link4</a></li>
<li><a href="link5.html>link5</a></li>
<li><a href="link6.html>link6</a></li>
Edit: Logic in the wrong spot, whoops!
Edit 2: Once more with logic placement.
I think this should work for you:
HtmlNodeCollection OneHome = document.DocumentNode.SelectNodes("//div[#id='accordion1']");
var OneHomelinks = OneHome.Descendants("a")
.Select(a => a.OuterHtml)
.ToList();
var headerCount = 0;
foreach (string link in OneHomelinks)
{
var prevCounter = headerCount;
if (link.Contains('#'))
{
headerCount++;
if (headerCount != 1 && headerCount > prevCounter) {
Response.Write("</ul>");
Response.Write("</p>");
Response.Write("</div>");
}
Response.Write("<div data-role=\"collapsible\" data-collapsed=\"true\">");
Response.Write("<h3>" + link + "</h3>");
Response.Write("<p>");
Response.Write("<ul>");
}
else {
Response.Write("<li>" + link + "</li>");
}
}
Response.Write("</ul>");
Response.Write("</p>");
Response.Write("</div>");

Conditionally change CSS class in Razor view

I need to change the CSS class of the <div> tag with the 'forumChild' class. It has to change every 3 loops of the foreach loop.
Is there a way to do this from within the control?
<div class="Forum">
<p>The Forum</p>
#foreach (var item in Model)
{
<div class="ForumChild">
<img src="#item.Blog.Image.img_path" alt="Not Found" />
<br />
#foreach (var comment in item.Blog.comment)
{
var db = new ACapture.Models.ACaptureDB();
var Name = from p in db.Profile.AsEnumerable()
where (p.AccountID == comment.AccountID)
select p;
<section>
<div>
<a href="#Url.Action("Index", "Home")">#foreach (var y in Name)
{ #(y.FirstName + " " + y.LastName + ":");
}</a>
</div>
<div>
#comment.Commentation
</div>
</section>
}
</div>
}
</div>
Thanks in advance
#{
int counter=0;
}
#foreach (var item in Model)
{
counter++;
<div class="#(counter<=3 ? "classRed":"classBlue")">
<img src="#item.Blog.Image.img_path" alt="Not Found" />
//other markup also here
</div>
if (counter == 6)
{
counter = 0;
}
}
Where classRed and classBlue are the CSS classes
How we handle this issue:
1) you need to create helper method that will return css class by some code.
string GetDivClass(int code)
{
var classes = new [] {"first", "second", "third"};
return classes[code];
}
2) create counter/index and increment it in the loop each time.
3) invoke helper method like GetDivClass(index % 3) at the div element.
PS
It is only POC, so don't use it in a real application (you need to add a validation logic and move 'classes' initialization to another place).
You can write any code you like into a Razor view, so to do what you're thinking of, you could do something like this (I left out most of the inner stuff):
#{
var className = "ForumChild";
}
<div>
#for (int i = 0; i < Model.Count; i++)
{
var item = Model[i];
if (i % 3 == 0)
className = GetNewClassName(); // Or whatever
<div class="#className">
</div>
}
</div>
You can add a counter variable to will start with 1 and increment in loop. Check with if statement is true by % and change the class name
#{ int counter = 1;}
#foreach (var item in Model)
{
if( (counter % 3) ==0 )
{
<div class="ChangedName">
}
else
{
<div class="ForumChild">
}
i++;

Categories