Copied to clipboard

Flag this post as spam?

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


  • bob baty-barr 1180 posts 1294 karma points MVP
    Mar 13, 2012 @ 15:45
    bob baty-barr
    0

    using razor templates, how would i loop through child or descendants

    I have a project need to be able to print the current page to a pdf or the pages below current 'chapter' or all pages below the 'book' but for the life of me, i cannot figure out how to mod the razor to build the pdf iterating down the tree.

    can someone share a code snippet? Here is what i was trying, but it is not getting the children of the current node...

    @foreach (var item in @Model.Children)
        {           
           <!-- Main content starts within page sequence -->
          <fo:page-sequence master-reference="master">
           
            <!-- Doucment header -->
            <fo:flow flow-name="header">
              <fo:block>
                <fo:inline font-family="Arial" font-size="23pt" color="#3399ff">
                  @item.Name
                </fo:inline>
              </fo:block>
            </fo:flow>
            
            <!-- Doucment footer -->
            <fo:static-content flow-name="footer">
              <fo:block font-size="8pt" color="#aaaaaa">
                <fo:block text-align-last="justify">
                  @item.Name by @item.WriterName - @DateTime.Now
                  
                  <fo:leader leader-pattern="space"/>
                  Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/>
                </fo:block>
              </fo:block>
            </fo:static-content>
            
            <!-- Document Body -->
            <fo:flow flow-name="xsl-region-body">
              <fo:block>
                 @ParseRichText(FoHelper.Instance.GetRichTextNodes(@item.BodyText))
              </fo:block>
              
              <!-- Having this before the closing tag of the body flow allows us to have a pager in the footer -->
              <fo:block id="last-page" keep-together.within-page="auto"></fo:block>
              
            </fo:flow>
          </fo:page-sequence>
          
    }   
  • bob baty-barr 1180 posts 1294 karma points MVP
    Mar 13, 2012 @ 15:59
    bob baty-barr
    0

    okay, so... this actually works... but makes a page for each subnode... how would i make it flow?

    @foreach (var item in @Model.DescendantsOrSelf())
        {          
           <!-- Main content starts within page sequence -->
          <fo:page-sequence master-reference="master">
            
            <!-- Doucment header -->
            <fo:flow flow-name="header">
              <fo:block>
                <fo:inline font-family="Arial" font-size="23pt" color="#3399ff">
                  @item.Name
                </fo:inline>
              </fo:block>
            </fo:flow>
            
            <!-- Doucment footer -->
            <fo:static-content flow-name="footer">
              <fo:block font-size="8pt" color="#aaaaaa">
                <fo:block text-align-last="justify">
                  @item.Name by @item.WriterName - @DateTime.Now
                  
                  <fo:leader leader-pattern="space"/>
                  Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/>
                </fo:block>
              </fo:block>
            </fo:static-content>
            
            <!-- Document Body -->
            
            <fo:flow flow-name="xsl-region-body">
              
              <fo:block>
                 @ParseRichText(FoHelper.Instance.GetRichTextNodes(@item.BodyText))
              </fo:block>
             
              <!-- Having this before the closing tag of the body flow allows us to have a pager in the footer -->
              <fo:block id="last-page" keep-together.within-page="auto"></fo:block>
        
            </fo:flow>
     
          </fo:page-sequence>
          
     }  
  • Darren Ferguson 1022 posts 3259 karma points MVP c-trib
    Mar 13, 2012 @ 18:49
    Darren Ferguson
    0

    Hi Bob, could you not just move:

    @foreach (var item in @Model.DescendantsOrSelf()) {
    }
    

    So it is inside:

    <fo:flow flow-name="xsl-region-body">
    

    e.g.

     <fo:flow flow-name="xsl-region-body">
    @foreach (var item in @Model.DescendantsOrSelf()) {
    <fo:block>
    
                 @ParseRichText(FoHelper.Instance.GetRichTextNodes(@item.BodyText))
              </fo:block>
    }
     </fo:flow>
    
  • bob baty-barr 1180 posts 1294 karma points MVP
    Mar 13, 2012 @ 19:29
    bob baty-barr
    0

    @darren, when i move it there i get the following error:

    Error loading MacroEngine script (file: )

  • Darren Ferguson 1022 posts 3259 karma points MVP c-trib
    Mar 13, 2012 @ 20:32
    Darren Ferguson
    0

    hey bob, that is a pretty generic error - i can't tell much from that. can you post the whole template? or mail it to me?

     

  • bob baty-barr 1180 posts 1294 karma points MVP
    May 25, 2012 @ 16:34
    bob baty-barr
    0

    so i eventually got this to work ALMOST exactly the way i wanted... HOWEVER, there is a caveat... as there always is...

    i have a structure...

    - book

    - - chapter1

    - - - page

    - - - page

    - - chapter2

    What i want, is for a pdf version of the book -- in sequence down the tree... i thought this was working...

     @foreach (var item in @Model.AncestorOrSelf(1).Children.Where("NodeTypeAlias == \"SPD\"").First().Descendants())
              
              <fo:block>
                <fo:inline font-family="Arial" font-size="23pt" color="#3399ff">
                  @item.Name
                </fo:inline>
              </fo:block>
              <fo:block>
                 @ParseRichText(FoHelper.Instance.GetRichTextNodes(@item.BodyText))
              </fo:block>
              }    

    BUT it is listing chapter1, chapter2, then the pages from chapter1 - i am terrible with razor, any thoughts?

     

  • Ravi Motha 290 posts 500 karma points MVP 7x c-trib
    May 25, 2012 @ 16:42
    Ravi Motha
    0

    so its listing that you are returning:

    chapter 1  

    chapter 2

    then chapter 1 content and

    chapter 2 content

     

     

  • Sebastiaan Janssen 5045 posts 15477 karma points MVP admin hq
    May 25, 2012 @ 16:43
    Sebastiaan Janssen
    0

    If I understand correctly, you only want:

    - chapter 1
    - chapter 2 

    You probably need to change your Descendants() to Children then.

    @foreach (var item in @Model.AncestorOrSelf(1).Children.Where("NodeTypeAlias == \"SPD\"").First().Children)
              { 
              <fo:block>
                <fo:inline font-family="Arial" font-size="23pt" color="#3399ff">
                  @item.Name
                </fo:inline>
              </fo:block>
              <fo:block>
                 @ParseRichText(FoHelper.Instance.GetRichTextNodes(@item.BodyText))
              </fo:block>
              }    
  • bob baty-barr 1180 posts 1294 karma points MVP
    May 25, 2012 @ 17:51
    bob baty-barr
    0

    i actually want each chapter an its pages in line... @Ravi was dead on with his interpretation... right now it is listing chapter 1, chapter2 then pages for chapter1 then pages for chapter2

    basically, i am looking for 'list entire structure from specified node'

  • bob baty-barr 1180 posts 1294 karma points MVP
    May 25, 2012 @ 18:14
    bob baty-barr
    0

    okay, so i was actually able to make this a bit shorter...

    @foreach (var item in @Model.AncestorOrSelf(1).Descendants("SPD").First().Descendants())

    however, Descendants() still not workign the way i would think -- why does it go all nodes at level2, then listing all level3?

    instead of level2 [subnodes] level2[subnodes]???

  • Tom Fulton 2030 posts 4998 karma points c-trib
    May 25, 2012 @ 19:05
    Tom Fulton
    0

    I think instead you should just use .Children to get the Chapters, then a loop inside that loop to get the pages?

    @foreach (var chapter in @Model.AncestorOrSelf(1).Descendants("SPD")) {
      this is a chapter

    @* Loop through each page in the current chapter *@
      @foreach (var page in chapter.Children) {
        this is a page in the chapter
      } 
    }

    -Tom

  • bob baty-barr 1180 posts 1294 karma points MVP
    May 25, 2012 @ 21:46
    bob baty-barr
    0

    can you nest a foreach? it is thowing generic error for me?

  • Tom Fulton 2030 posts 4998 karma points c-trib
    May 25, 2012 @ 21:50
    Tom Fulton
    1

    Yep, you definitely can!

    Where is the error occuring and what is it (anything helpful?)?  Maybe paste your updated code?

    -Tom

  • bob baty-barr 1180 posts 1294 karma points MVP
    May 25, 2012 @ 21:55
    bob baty-barr
    0

    @Tom -- thanks a ton!

    first, here is my silly error - not much help

    Error loading MacroEngine script (file: )

    next - here is my full template [yes, please note it is a template] umbraco 4.7.1.1

    <%@ Master Language="C#" MasterPageFile="~/masterpages/PDFMaster.master" AutoEventWireup="true" %>
    <asp:content ContentPlaceHolderId="PdfContentPlaceHolder" runat="server">
     <umbraco:Macro  runat="server" language="cshtml">
    @inherits umbraco.MacroEngines.DynamicNodeContext
    @using FergusonMoriyama.Pdf
    @using System.Xml
    @using umbraco.IO
        
        @{
          Response.ContentType = "text/xml";
          Response.AppendHeader("X-Pdf-Render","true");
      
          // -- Uncomment this to force the browser to download the PDF.
       //Response.AppendHeader("X-Pdf-Force-Download",@Model.Name);
        }
        
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:ibex="http://www.xmlpdf.com/2003/ibex/Format">
           <!-- Sets standard PDF Metadata -->
          <ibex:properties
            title="@Model.Name"
            author="@Model.WriterName"
            subject=""
            keywords="metat,bacon,sheep"
            creator="PDF Creator for Umbraco" />

          <!-- Uncomment below to add protection to the PDF - optionally specify a password -->
          <!-- <ibex:security deny-print="true" deny-extract="true" deny-modify="true" user-password="" owner-password=""/> -->

          <!-- This defines a simple page layout with a heder and a footer -->
          <!-- See http://www.w3schools.com/xslfo/obj_layout-master-set.asp -->
          <fo:layout-master-set>
            <fo:simple-page-master master-name="master" page-width="210mm" page-height="297mm" margin-top="1cm" margin-bottom="1cm" margin-left="1cm" margin-right="1cm">
              <fo:region-body margin-top="1.5cm" margin-bottom="1.5cm" column-count="1" column-gap="0.5cm"/>
              <fo:region-before region-name="header" extent="3cm"/>
              <fo:region-after region-name="footer" extent="1.5cm"/>
            </fo:simple-page-master>
          </fo:layout-master-set>
          
           <!-- Main content starts within page sequence -->
          <fo:page-sequence master-reference="master">
            
            <!-- Doucment header -->
            <fo:flow flow-name="header">
              <fo:block>
                <fo:inline font-family="Arial" font-size="23pt" color="#3399ff">
                  @Model.AncestorOrSelf(2).Name
                </fo:inline>
              </fo:block>
            </fo:flow
            
            <!-- Doucment footer -->
            <fo:static-content flow-name="footer">
              <fo:block font-size="8pt" color="#aaaaaa">
                <fo:block text-align-last="justify">
                  @Model.Name by @Model.WriterName - @DateTime.Now
                  
                  <fo:leader leader-pattern="space"/>
                  Page <fo:page-number/> of <fo:page-number-citation ref-id="last-page"/>
                </fo:block>
              </fo:block>
            </fo:static-content>
           
            <!-- Document Body -->
            <fo:flow flow-name="xsl-region-body">
              @foreach (var chapter in @Model.AncestorOrSelf(1).First().Children.Where("NodeTypeAlias == \"SPD\""))
             
              <fo:block>
                <fo:inline font-family="Arial" font-size="23pt" color="#3399ff">
                  @chapter.Name
                </fo:inline>
              </fo:block>
              <fo:block>
                 @ParseRichText(FoHelper.Instance.GetRichTextNodes(@chapter.BodyText))
              </fo:block>
              @foreach (var page in chapter.Children()) {
                <fo:block>
                <fo:inline font-family="Arial" font-size="23pt" color="#3399ff">
                  @page.Name
                </fo:inline>
              </fo:block>
              <fo:block>
                 @ParseRichText(FoHelper.Instance.GetRichTextNodes(@page.BodyText))
              </fo:block>
                
              }           
              <!-- Having this before the closing tag of the body flow allows us to have a pager in the footer -->
              <fo:block id="last-page" keep-together.within-page="auto"></fo:block>
              
            </fo:flow>
            
          </fo:page-sequence>
          
        </fo:root>
       
        @helper ParseElement(XmlNode node) { 
          <!-- @node.Name -->
          switch(node.Name) 
          {
            case "p":
              <fo:block margin-bottom="0.5cm">
                @ParseRichText(node.ChildNodes)
              </fo:block>
              break;
            case "strong":
              <fo:inline font-weight="bold">
                @ParseRichText(node.ChildNodes)
              </fo:inline>
              break;
            case "em":
              <fo:inline font-style="italic">
                @ParseRichText(node.ChildNodes)
              </fo:inline>
              break;
            case "a":
              <fo:basic-link color="blue" text-decoration="underline" external-destination="url('@node.Attributes["href"].Value')">
                @ParseRichText(node.ChildNodes)
              </fo:basic-link>
              break;
            case "u":
              <fo:inline text-decoration="underline">
                @ParseRichText(node.ChildNodes)
              </fo:inline>
              break;
            case "ol":
              <fo:list-block margin-bottom="0.5cm">
                @ParseRichText(node.ChildNodes)
              </fo:list-block>
              break;
            case "ul":
              <fo:list-block margin-bottom="0.5cm">
                @ParseRichText(node.ChildNodes)
              </fo:list-block>
              break;
            case "li":
              <fo:list-item>
                <fo:list-item-label>
                  <fo:block>-</fo:block>
                </fo:list-item-label>
                <fo:list-item-body>
                  <fo:block margin-left="0.5cm">
                   @ParseRichText(node.ChildNodes)
                  </fo:block>
                </fo:list-item-body>
              </fo:list-item>
              break;
            case "img":
              var docRoot = IOHelper.MapPath("~/");
              <fo:block>
                <fo:external-graphic src="@docRoot/@node.Attributes["src"].Value" content-width="9cm"/>
              </fo:block>
              @ParseRichText(node.ChildNodes)
              break;
          }
      }

      @helper ParseRichText(XmlNodeList nodes) {
        foreach(XmlNode node in nodes) {
           
           switch(node.NodeType)
           {
               case XmlNodeType.Text:
                 @node.Value
                 @ParseRichText(node.ChildNodes);
                 break;
               case XmlNodeType.Element:
                 @ParseElement(node);
                 break;
               default:
                 @ParseRichText(node.ChildNodes);
                 break;
           }
        }
      }
      </umbraco:Macro>
     
    </asp:Content>
  • Tom Fulton 2030 posts 4998 karma points c-trib
    May 25, 2012 @ 21:58
    Tom Fulton
    0

    Hmm, weird error, it disappears if you remove the second loop?

    This might be your problem, try chapter.Children instead of chapter.Children()

  • bob baty-barr 1180 posts 1294 karma points MVP
    May 25, 2012 @ 22:01
    bob baty-barr
    0

    yeah, sorry... that was in there for a second test option -- me hacking...

    took it out, same result...

    if i take out the second @foreach i get output of the chapter level, yes - but nothing else.

  • Tom Fulton 2030 posts 4998 karma points c-trib
    May 25, 2012 @ 22:04
    Tom Fulton
    0

    Wonder if you can get a better error with ?umbdebugshowtrace and checking the trace?

  • bob baty-barr 1180 posts 1294 karma points MVP
    May 25, 2012 @ 22:28
    bob baty-barr
    0

    got much better error results... taking about not needing a second @ for the nested for each... took that out... then i get

    There are multiple root elements. Line 69, position 2

    hmmmm any thoughts?

  • Tom Fulton 2030 posts 4998 karma points c-trib
    May 25, 2012 @ 22:31
    Tom Fulton
    0

    That sounds like an XML issue, maybe something with your ParseRichText or ParseElement calls.  Maybe the BodyText of one of the Page nodes has some bad XML

  • Ravi Motha 290 posts 500 karma points MVP 7x c-trib
    May 25, 2012 @ 22:53
    Ravi Motha
    0

    Hye bob, sorry was on a train with dodgy internet.. I suspect Tom is right.

    because a you can nest foreach, like you can anywhere else.

     

    when you are processeing the content I suspect it might lso be laid out in nodes and you can use the model to get the right values or you just need to escape something.

    you effectively need to see the data in the "duff node" and see what you have.

    it might be the value is arranged like this <nodeblah>hfbsdhfsdhf</nodeblah><nodebla2>vhsdbfhfsb</nodebla2> so you just need to handle it..

     

    ravi

Please Sign in or register to post replies

Write your reply to:

Draft