Part 3 of the feature walkthrough continues with features
available in the TAFKA 4.6.2 release.
Today, I'm covering locating ancestors, the XML helpers and
Extension Methods and the XPath helper
RC1 is just around the corner and there's a bunch more features
coming - i'll try and cover those too
AncestorOrSelf
The 4.6.1 version of Razor had an implementation of
AncestorOrSelf that took a Func<DynamicNode,bool> as a
predicate to decide when to stop ascending the node tree.
In 4.7, there's now a parameterless implementation that will climb
to the top of the node tree and return the top most
grandparent.
Here's an example:
var Node = @Model.NodeById(1640);
var Home = Node.AncestorOrSelf();
@Home.Name;
Ancestors
Sometimes you want to get a list of the parents walking up the
tree.
For this, you can use .Ancestors on the node:
var Node = @Model.NodeById(1640);
@foreach(var level in Node.Ancestors)
{
<li><a href="@level.Url">@level.Name</a></li>
}
Ancestors and AncestorOrSelf have been improved in RC1 - more on
that in a later part!
Type Safety
In 4.6.1, when a property was returned by the @ syntax, the type
was always string.
This meant that sometimes when you really wanted a boolean or
integer, you had to do typecasting within your razor template.
Assuming the properties I'm using below exist on your Document
types,
In 4.7, we've improved this so that you can simply go:
if(@Model.shouldBeVisible){
//Do something
}
//or
if(@Model.catCount > 1)
{
//Do something
}
Warning: this change may break a few of your
existing templates but was needed to support some more of the
advanced features.
If you have if statements or similar that are checking against
strings, they'll need to be refactored slightly.
//instead of:
if(@Model.shouldBeVisible == "1")
//use:
if(@model.shouldBeVisible)
Supported types are currently:
string, int, decimal, bool, xml (see below for xml)
XML Properties
If you have a field which contains valid XML, and wasn't
generated from an RTE, DynamicNode will detect this and allow you
to
access it with . notation
If there's more than one node with the same name, you'll need to
use [] indexing to access the element you want
Here's an example:
@Model.xmlProperty.Catalog.Books[1].Genre
Warning: the property access is case sensitive.
Make sure you check your case.
The root node is removed, so omit that, and remember to check for
indexing if you have multiple nodes that might be returned.
If the XML function is kicking in, your root node may need to be
excluded - check umbracoSettings.config for an override of document
element types that shouldn't be converted
Custom Extension Methods
When working with DynamicNodeList, sometimes you need some
functionality that we haven't provided.
We've added support for calling your own Mix-Ins against the
DynamicNodeList type.
Here's an example that we've been using for testing:
This random method has been included in the core distribution
for 4.7 but we've included it below so that you can see how to
write one
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using umbraco.MacroEngines;
namespace SniperSystems.Umbraco.Razor.Extensions
{
public static class RazorExtensions
{
public static DynamicNodeList Random(this DynamicNodeList all, int Min, int Max)
{
//get a random number generator
Random r = new Random();
//choose the number of elements to be returned between Min and Max
int Number = r.Next(Min, Max);
//Call the other method
return Random(all, Number);
}
public static DynamicNodeList Random(this DynamicNodeList all, int Max)
{
//Randomly order the items in the set by a Guid, Take the correct number, and return this wrapped in a new DynamicNodeList
return new DynamicNodeList(all.Items.OrderBy(x => Guid.NewGuid()).Take(Max));
}
}
}
Put this in a new class library and compile it.
Drop the DLL in your bin folder, and now you can do this:
@ForEach(@Model.Children.Random(8))
{
//Working with 8 randomly selected Children
}
Unlike the Alliance's
way of implementing Random, there's no chance of a single node
coming back more than once in your random selection - Unique nodes
only!
There are 3 overloads to Random in the 4.7 distribution:
Random() will return a single randomly selected node from the
collection
Random(int number) will return N randomly selected nodes from the
collection
Random(int min, int max) will return between min and max randomly
selected nodes from the collection
XPath helper
Sometimes .Where isn't enough to select the node you want - it
only works on the current node, and you can't easily check
Parents/Children
We've added a .XPath helper which lets you use XPath to select the
nodes.
The XPath you use is used to select nodes from the original XML
which are then upgraded to NodeFactory.Node and then
DynamicNode
@foreach(var item in @Model.XPath("//ChildItem[catCount > 4 and count(.//catPictures) > 0]").Random(4))
{
@item.Name<br/>
}
The .XPath helper also works on a DynamicXml item (from an XML
property) but won't do the upgrade to DynamicNode/DynamicNodeList
like when you call it directly on @Model
We're really very sorry we had to provide something that was
similar to XSLT, but it does add a lot of functionality :)
I'm Gareth Evans, Follow me at @agrath on twitter, and here's a
few links:
The new Razor forum on our.umbraco: http://our.umbraco.org/forum/developers/razor
Codeplex for any feature requests or bugs: http://umbraco.codeplex.com/
Read more from the Umbraco Razor walkthrough series
Part 1
Part 2
Part 3
Part 4
Part 5
Part 6
Part 7
Part 8