Really excited to start doing this - am quite fluent with XSLT but I don't like how it reads, especially when you start getting pretty complex with <xsl:attribute> and <xsl:choose>
Trying to render this HTML snippet with Razor
<ul>
<li><a href="url">name</a></li>
<li><a href="url">name</a></li>...
<li class="last"><a href="url">name</a></li>
</ul>
Because we want to know the position (to do class="last"), we've tried a few different techniques just playing around.
First we were wondering how to calculate the position when using @ForEach
The only way we could find to do this was
var i = 0;
@ForEach(var page in Model.Children)
{
i++;//now i contains position() [from xslt]
}
However, we'd need to know the length to be able to check i against this.
Model.Children.length doesn't work,
Here's our usings
@using System;
@using System.Collections.Generic;
@using System.Linq;
@using System.Web;
And when we try this:
@Model.Children.ElementAt(2)
we get:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'ElementAt' at CallSite.Target(Closure , CallSite , Object , Int32 ) at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1) at RazorEngine.Dynamic.fcddcebbcff.Execute() at RazorEngine.Templating.TemplateService.Parse[T](String template, T model, String name) at umbraco.MacroEngines.RazorEngine.GetResult(String cacheIdentifier, String template, INode currentPage, String& result)
This suggests that @Model.children is IEnumerable<object> or List<object> but cast into object (the list itself is object)
If we try this:
@Model.Children.Count()
we get a similar error:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'Count' at CallSite.Target(Closure , CallSite , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0) at RazorEngine.Dynamic.bdabbedd.Execute() at RazorEngine.Templating.TemplateService.Parse[T](String template, T model, String name) at umbraco.MacroEngines.RazorEngine.GetResult(String cacheIdentifier, String template, INode currentPage, String& result)
Pretty sure the same would apply for .length & friends.
Have tried casting Children to a List<DynamicNode>
@(((List<DynamicNode>Model.Children).Count())
that gives:
error CS0305: Using the generic type 'System.Collections.Generic.List' requires 1 type arguments
error CS0103: The name 'DynamicNode' does not exist in the current context
error CS0305: Using the generic type 'System.Collections.Generic.List' requires 1 type arguments
error CS0119: 'umbraco.MacroEngines.DynamicNode' is a 'type', which is not valid in the
given context
Have also tried the above examples with
@Model.textPages.ElementAt(2) and friends;
where textPages is the document type alias
The only thing we could get to work is this:
@{
var list = new List<umbraco.MacroEngines.DynamicNode>();
foreach(var item in Model.Children)
{
list.Add(item);
}
@list.Count()
@list.ElementAt(2).Name
@list.ElementAt(2).Url
That is to say, copying the list using a foreach into a defined list with type, then all the methods we expect work.
Obviously, we could now combine this with another foreach loop, i++ etc and check the length.
Finally, the last thing we were wondering, though this is probably something for another post is can anyone think of a way we can use Partial Views, that is; a way to store a block of HTML somewhere and then reuse it either within that page or within multiple pages?
Sort of like we'd do with named templates and xslt include.
I suppose we could define a function that accepts a dynamic node and then call that function? Probably wouldn't work cross-template though.
Good idea. I went a bit further and patched the DynamicNode class and all the surrounding Razor stuff to support this as well as things like parameters not coming through. Hoping it will get assessed for 4.6.2
So at the moment, your answer would serve well for anyone running 4.6.1
Good to hear! There is a *ton* of stuff in uComponents' uQueryExtensions that (I think) needs to be brought into core, especially to support Razor syntax. I don't think I'd be able to use Razor without it. And then bring in parameters and "BAM", Razor's a go!
It seems you've located my original blog post from before I added all the dynamic node features and joined the core team! Yes, all the features are 4.7+
razor questions, type safety etc
Hi Guys,
Trying out the new Razor syntax in umbraco 4.6.1.
Really excited to start doing this - am quite fluent with XSLT but I don't like how it reads, especially when you start getting pretty complex with <xsl:attribute> and <xsl:choose>
Trying to render this HTML snippet with Razor
<ul>
<li><a href="url">name</a></li>
<li><a href="url">name</a></li>...
<li class="last"><a href="url">name</a></li>
</ul>
Because we want to know the position (to do class="last"), we've tried a few different techniques just playing around.
First we were wondering how to calculate the position when using @ForEach
The only way we could find to do this was
var i = 0;
@ForEach(var page in Model.Children)
{
i++; //now i contains position() [from xslt]
}
However, we'd need to know the length to be able to check i against this.
Model.Children.length doesn't work,
Here's our usings
@using System;
@using System.Collections.Generic;
@using System.Linq;
@using System.Web;
And when we try this:
@Model.Children.ElementAt(2)
we get:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'ElementAt' at CallSite.Target(Closure , CallSite , Object , Int32 ) at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1) at RazorEngine.Dynamic.fcddcebbcff.Execute() at RazorEngine.Templating.TemplateService.Parse[T](String template, T model, String name) at umbraco.MacroEngines.RazorEngine.GetResult(String cacheIdentifier, String template, INode currentPage, String& result)
This suggests that @Model.children is IEnumerable<object> or List<object> but cast into object (the list itself is object)
If we try this:
@Model.Children.Count()
we get a similar error:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'Count' at CallSite.Target(Closure , CallSite , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0) at RazorEngine.Dynamic.bdabbedd.Execute() at RazorEngine.Templating.TemplateService.Parse[T](String template, T model, String name) at umbraco.MacroEngines.RazorEngine.GetResult(String cacheIdentifier, String template, INode currentPage, String& result)
Pretty sure the same would apply for .length & friends.
Have tried casting Children to a List<DynamicNode>
@(((List<DynamicNode>Model.Children).Count())
that gives:
error CS0305: Using the generic type 'System.Collections.Generic.List' requires 1 type arguments
error CS0103: The name 'DynamicNode' does not exist in the current context
So we'll add a namespace:
@(((List<umbraco.MacroEngines.DynamicNode>Model.Children).Count())
this gives:
error CS0305: Using the generic type 'System.Collections.Generic.List' requires 1 type arguments
error CS0119: 'umbraco.MacroEngines.DynamicNode' is a 'type', which is not valid in the
given context
Have also tried the above examples with
@Model.textPages.ElementAt(2) and friends;
where textPages is the document type alias
The only thing we could get to work is this:
@{
var list = new List<umbraco.MacroEngines.DynamicNode>();
foreach(var item in Model.Children)
{
list.Add(item);
}
@list.Count()
@list.ElementAt(2).Name
@list.ElementAt(2).Url
That is to say, copying the list using a foreach into a defined list with type, then all the methods we expect work.
Obviously, we could now combine this with another foreach loop, i++ etc and check the length.
Finally, the last thing we were wondering, though this is probably something for another post is can anyone think of a way we can use Partial Views, that is; a way to store a block of HTML somewhere and then reuse it either within that page or within multiple pages?
Sort of like we'd do with named templates and xslt include.
I suppose we could define a function that accepts a dynamic node and then call that function? Probably wouldn't work cross-template though.
Thanks in advance
Gareth
We'd like to do something like this:
@foreach(var page in Model.Children)
{
<li @((Model.Children.Count() == page.IndexOf()) ? class='last-menu' : "")>
<a href='@page.Url'>@page.Name</a></li>
</li>
}
Hi Gareth
If you look into using uComponents (http://ucomponents.codeplex.com/) you can accomplish that with something like:
cheers
Jonathan
Hi Jonathan
Good idea.
I went a bit further and patched the DynamicNode class and all the surrounding Razor stuff to support this as well as things like parameters not coming through.
Hoping it will get assessed for 4.6.2
So at the moment, your answer would serve well for anyone running 4.6.1
Gareth
Good to hear! There is a *ton* of stuff in uComponents' uQueryExtensions that (I think) needs to be brought into core, especially to support Razor syntax. I don't think I'd be able to use Razor without it. And then bring in parameters and "BAM", Razor's a go!
Not sure if it works prior to 4.7.1, but I'm doing it like this:
Hi,
It seems you've located my original blog post from before I added all the dynamic node features and joined the core team!
Yes, all the features are 4.7+
Gareth
is working on a reply...
This forum is in read-only mode while we transition to the new forum.
You can continue this topic on the new forum by tapping the "Continue discussion" link below.