I like elegant code, especially in my Razor templates, and I found myself repeatedly having to write @foreach loops with a counter variable (e.g. int i = 0; i++) in order to track what node I was iterating over. In part 6, I introduced a new method called Index (aliased as position) which lets you get the current position.
This index property has been combined with the parent and children methods on DynamicNode to solve a lot of your standard requirements when iterating over nodes and generating HTML. Since generating HTML is the primary job of Razor, so we want it to be as concise and as quick as possible.
IsHelper (this is the internal name) methods all work the same, and have 3 overloads. They're basically ternary operators, but work a little nicer in that they're easy to embed in properties and quicker to write as you don't need so many brackets to make Razor understand them. The general idea behind IsHelper is to allow you to dynamically inject class names and style attributes onto your nodes, based on their position within the list you're iterating. You can use this for a variety of things such as alternating row colours or fixing the margin/padding on the first/last item etc.
All DynamicNodes (except for the top most node) belong to a set, whether that's their parents list, or a special set created in context such as the result from Ancestors This means that when you're iterating over a set, the node will belong to that set, no matter where the original node was sourced from in the tree. What this means is that each node as you iterate has a concept of the list that contains it (that you are iterating) so a method call to that node can determine it's position in the iteration.
Here are the overloads: IsHelper() => bool IsHelper(string valueIfTrue) => valueIfTrue || emptyString IsHelper(string valueIfTrue, string valueIfFalse) => valueIfTrue || valueIfFalse
IsHelper is just an internal name though, so when calling them, you use the name of the specific IsHelper you want. These are: IsFirst If this is the first node in a set IsNotFirst If this is not the first node in a set IsLast If this is the last node in a set IsNotLast You guessed it! If this is not the last node in a set IsPosition, IsNotPosition Is the current node at index? Example: @item.IsPosition(3) IsModZero, IsNotModZero Is the current node position evenly dividable (modulus) by a given number? Will be true for every 3rd node: @item.IsModZero(3) IsEven, IsOdd Shorthand versions for IsModZero(2) and IsNotModZero(2)
Start new div tag after 4th Item
Hi, how would I go about starting a new list in a new div tag once the previous list has reached 4 items?
So far I have :
@{var param = Parameter.dataType;}
<div class="row">
@foreach (var item in @Model.AncestorOrSelf().Descendants(param))
{
<div class="item"><a href="@item.Url">@item.Name</a>
</div>
}
</div>
this currently lists all my items in one big div class row.
I want to start the div tag row, fill it with 4 items, close the tag and then start a new div tag and fill it with another 4 items and repeat etc..
I'd imagine I would have to write the first 4 items to a HTML string and then wrap that in the div tags or something ??
Any help would be appreciated, Thank You!
Hi Charly
You can use a for loop and use the index to write out the opening and closing tags i.e.
This has not been tested so use as a guide only. Hope this helps,
Tony
Check out http://umbraco.com/follow-us/blog-archive/2011/9/18/umbraco-razor-feature-walkthrough%E2%80%93part-7.aspx on how to use the Is helpers:
IsHelper
I like elegant code, especially in my Razor templates, and I found myself repeatedly having to write @foreach loops with a counter variable (e.g. int i = 0; i++) in order to track what node I was iterating over. In part 6, I introduced a new method called Index (aliased as position) which lets you get the current position.
This index property has been combined with the parent and children methods on DynamicNode to solve a lot of your standard requirements when iterating over nodes and generating HTML. Since generating HTML is the primary job of Razor, so we want it to be as concise and as quick as possible.
IsHelper (this is the internal name) methods all work the same, and have 3 overloads. They're basically ternary operators, but work a little nicer in that they're easy to embed in properties and quicker to write as you don't need so many brackets to make Razor understand them.
The general idea behind IsHelper is to allow you to dynamically inject class names and style attributes onto your nodes, based on their position within the list you're iterating. You can use this for a variety of things such as alternating row colours or fixing the margin/padding on the first/last item etc.
All DynamicNodes (except for the top most node) belong to a set, whether that's their parents list, or a special set created in context such as the result from Ancestors
This means that when you're iterating over a set, the node will belong to that set, no matter where the original node was sourced from in the tree.
What this means is that each node as you iterate has a concept of the list that contains it (that you are iterating) so a method call to that node can determine it's position in the iteration.
Here are the overloads:
IsHelper() => bool
IsHelper(string valueIfTrue) => valueIfTrue || emptyString
IsHelper(string valueIfTrue, string valueIfFalse) => valueIfTrue || valueIfFalse
IsHelper is just an internal name though, so when calling them, you use the name of the specific IsHelper you want.
These are:
IsFirst
If this is the first node in a set
IsNotFirst
If this is not the first node in a set
IsLast
If this is the last node in a set
IsNotLast
You guessed it! If this is not the last node in a set
IsPosition, IsNotPosition
Is the current node at index? Example: @item.IsPosition(3)
IsModZero, IsNotModZero
Is the current node position evenly dividable (modulus) by a given number? Will be true for every 3rd node: @item.IsModZero(3)
IsEven, IsOdd
Shorthand versions for IsModZero(2) and IsNotModZero(2)
Ok so far I've got :
@{var param = Parameter.dataType;}
@foreach (var item in @Model.AncestorOrSelf().Descendants(param))
{
if(@item.IsFirst() || @item.IsModZero(4)){
<div class="row">
}
<div class="item"><a href="@item.Url">@item.Name</a></div>
if(@item.IsLast() || @item.IsModZero(4)){
</div>
}
}
Thanks to Tony and Dan! But my second if statement is not being picked up as Razor, it's being rendered as HTML.
I tried wrapping it in @{} but I get an error "The foreach block is missing a closing "}" character."
I tried using just @ but still no luck. What am I missing?
Hi Charly,
Here's my solution - not the most elegant for sure, would like to see how to use the helpers for this:
Cheers,
Sara
This might be easier :) https://gist.github.com/1067257
Jeroen
Thanks Jeroen for the answer, saved me a lot of time.
Aha! Thanks =)
@Jeroen - Thanks for your code. Helped me group a large number of items together to form columns.
I would add an extra number in case your division is returning a reminder.
is working on a reply...