Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Gareth Evans 142 posts 334 karma points c-trib
    Jan 20, 2011 @ 04:31
    Gareth Evans
    0

    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

  • Gareth Evans 142 posts 334 karma points c-trib
    Jan 20, 2011 @ 04:38
    Gareth Evans
    0

    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>

        }

  • Jonathan Lathigee 56 posts 99 karma points
    Feb 11, 2011 @ 23:24
    Jonathan Lathigee
    1

    Hi Gareth

    If you look into using uComponents (http://ucomponents.codeplex.com/) you can accomplish that with something like:

                var nodes = uQuery.GetCurrentNode().GetChildNodes();
                int nodeCount = nodes.Count();
                int i = 1;

                foreach (var page in nodes)
                {
                   <li @((nodeCount == i) ? class='last-menu' : "")>
    <a href='@page.Url'>@page.Name</a></li> 
     </li>

                    i++;
                }

     

    cheers

    Jonathan

  • Gareth Evans 142 posts 334 karma points c-trib
    Feb 13, 2011 @ 20:22
    Gareth Evans
    0

    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

  • Jonathan Lathigee 56 posts 99 karma points
    Feb 14, 2011 @ 18:08
    Jonathan Lathigee
    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!

  • Rasmus Lynggaard 118 posts 325 karma points
    Mar 06, 2012 @ 15:16
    Rasmus Lynggaard
    0

    Not sure if it works prior to 4.7.1, but I'm doing it like this:

    @{
    var children =Model.Children;
    if(children.Count()>0)
    {
     
    <ul>
     
    @foreach(var child in children)
     
    {
       
    var classes ="";
        classes +
    = child == children.First()?" first":"";
        classes
    += child == children.Last()?" last":"";
       
    var className =!string.IsNullOrEmpty(classes.Trim())?string.Format(" class=\"{0}\"", classes.Trim()):"";
       
    <li@Html.Raw(className)><a href="@child.Url">@child.Name</a>
      }
      </
    ul>
    }
    }
  • Gareth Evans 142 posts 334 karma points c-trib
    Mar 06, 2012 @ 19:27
    Gareth Evans
    0

    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

Please Sign in or register to post replies

Write your reply to:

Draft