Copied to clipboard

Flag this post as spam?

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


  • Dan 1285 posts 3917 karma points c-trib
    May 24, 2010 @ 17:21
    Dan
    0

    Add wrapper div conditionally

    Hi,

    I have a feeling I'm approaching this in a very non-xslt way.  Basically I have the code below, which works okay, but rather than all records being contained within a div with a class of "image-group", I want every group of 4 records to be within a div with a class of "image-group".

    The code I have is:

    <xsl:template match="/">

    <div id="landscape-container">
    <div class="image-group">
    <xsl:for-each select="$currentPage/node [string(data [@alias='umbracoNaviHide']) != '1']">
    <xsl:variable name="mediaId" select="data [@alias = 'mainImage']"/>
    <div>
    <xsl:choose>
    <xsl:when test="(position() mod 4) = 0">
    <xsl:attribute name="class">
    <xsl:value-of select="string('x d')" />
    </xsl:attribute>
    </xsl:when>
    <xsl:otherwise>
    <xsl:attribute name="class">
    <xsl:value-of select="string('x')" />
    </xsl:attribute>
    </xsl:otherwise>
    </xsl:choose>
    <a href="{umbraco.library:NiceUrl(@id)}">LINK</a>
    </div>
    </xsl:for-each>
    </div>
    </div>
    </xsl:template>

    I've tried dynamically inserting the open and close div tags within the loop, but it's erroring because of unclosed tags.  So I'm thinking this perhaps lends itself better to something like XSLT templates, but I'm not sure where to start.

    Is this the right approach?  Can someone nudge me in the right direction?

    Thanks all.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    May 24, 2010 @ 17:30
    Morten Bock
    1

    Grouping is a classic challenge. This page has a couple of links on how to group by position:

    http://www.jenitennison.com/xslt/grouping/

    Basically, you will want to select every 4th item, and for each of them, render itself and the following 3 siblings. This can be done both with templates or nested for-each loops.

    Let me know if this is total jibberish?

  • Dan 1285 posts 3917 karma points c-trib
    May 24, 2010 @ 19:31
    Dan
    0

    Thanks Morten.  I've had a look at that reference and have also done a bit of 'group by postion' research.  However, when I apply this to my scenario above, I just get the feeling I'm not doing it right.  The following is kind of working in that it's grouping things into divs (just pulling the id of a media field out to test with) but it's the next part I'm struggling with; do I need to duplicate the bulk of the code in the middle to output the images 4 times (one for $nodes[1], again for $nodes[2] etc)?  Seems like it should be more elegant than that?

     

    <xsl:variable name="itemsPerDiv" select="4"/>

    <xsl:template match="/">
        <div id="landscape-container">
            <xsl:call-template name="groupedItems">
                    <xsl:with-param name="nodes" select="$currentPage/node [string(data [@alias='umbracoNaviHide']) != '1']"/>
            </xsl:call-template>
        </div>
    </xsl:template>

    <xsl:template name="groupedItems">
        <xsl:param name="nodes"/>
        <div class="image-group">
            <div class="xcontainer">
                <div class="x a">
                    1. <xsl:value-of select="$nodes[1]/data [@alias='mainImage']"/><br />
                    2. <xsl:value-of select="$nodes[2]/data [@alias='mainImage']"/><br />
                    3. <xsl:value-of select="$nodes[3]/data [@alias='mainImage']"/><br />
                    4. <xsl:value-of select="$nodes[4]/data [@alias='mainImage']"/><br />
                </div>
            </div>
        </div>
        <xsl:if test="count($nodes) > $itemsPerDiv">
            <xsl:call-template name="groupedItems">
                <xsl:with-param name="nodes" select="$nodes[position() > $itemsPerDiv]"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    May 25, 2010 @ 10:11
    Morten Bock
    1

    If you do something like this, then you can write you layout for the nodes in the renderNode template:

       <xsl:template match="/">
            <xsl:variable name="itemsPerGroup" select="6"/>
            <xsl:for-each select="$currentPage/node [position() mod $itemsPerGroup = 1]">
                <div class="group">
                    <xsl:call-template name="renderNode">
                        <xsl:with-param name="dataNode" select="." />
                    </xsl:call-template>
                    <xsl:for-each select="./following-sibling::node [position() &lt; $itemsPerGroup]">
                        <xsl:call-template name="renderNode">
                            <xsl:with-param name="dataNode" select="." />
                        </xsl:call-template>
                    </xsl:for-each>
                </div>
            </xsl:for-each>
        </xsl:template>
    
        <xsl:template name="renderNode">
            <xsl:param name="dataNode"/>
            <div class="item">
                <xsl:value-of select="$dataNode/@id"/>
            </div>
        </xsl:template>
    
  • Søren Linaa 255 posts 208 karma points
    Aug 23, 2010 @ 18:42
    Søren Linaa
    0

    Hi - Do you know if it's possible to sort the nodes before grouping them ?

    Let's say I want to group by a date.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Aug 23, 2010 @ 19:21
    Morten Bock
    0

    Not sure this approach is the one to go with, since this just groups x items together.

    Is it for something like a news archive grouped by year/month or something like that?

  • Søren Linaa 255 posts 208 karma points
    Aug 23, 2010 @ 19:25
    Søren Linaa
    0

    Hi Morten,

    It's for an event cycle. I need 4 events under the same div to make my jquery cycle happy.

    Actually I have made my xpathnodeiterator in c# but couldn't figure out how to sort the list. But the best approach must be to have the sorted input before doing more with xslt.

     

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Aug 23, 2010 @ 19:35
    Morten Bock
    0

    Ahh, so getting events in groups of 4, sorted by date. Will give it a spin....

    Are you using the new or the old xml schema?

  • Søren Linaa 255 posts 208 karma points
    Aug 23, 2010 @ 20:01
    Søren Linaa
    0

    Morten, that will be great

    Yes I need a group by 4 and sorted by date.  Actually I'm using my own xslt lib - so my foreach loop looks like this.

      <xsl:for-each select="XsltLibrary:GetAllEvents($source)/events/event"> 

     

    my xml look like

    <events>
    <event startDate="16-08-2010 00:00:00"
    more data.....
    </event>
    <event startDate="16-08-2010 00:00:00"
    more data.....
    </event>

    <events>

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Aug 23, 2010 @ 21:29
    Morten Bock
    2

    Hmm, I had to "cheat" a bit, by doing it in two steps. First saving the sorted events, and then doing the grouping, But it works :-)

        <xsl:variable name="sortedEvents">
        <xsl:for-each select="XsltLibrary:GetAllEvents($source)/events/event">
          <xsl:sort select="concat(substring(@startDate,7,4),substring(@startDate,4,2),substring(@startDate,1,2))" data-type="text"/>
          <xsl:copy-of select="."/>
        </xsl:for-each>
        </xsl:variable>
        <root>
        <xsl:for-each select="msxsl:node-set($sortedEvents)/event[position() mod 4 = 1]">
          <group>
            <xsl:for-each select=". | ./following-sibling::event [position() &lt; 4]">
              <xsl:copy-of select="."/>
            </xsl:for-each>
          </group>
        </xsl:for-each>
        </root>
    
  • Søren Linaa 255 posts 208 karma points
    Aug 23, 2010 @ 22:04
    Søren Linaa
    0

    Thank you Morten - it sure works.

    I'll buy you a beer next time - Cheers  :-)

  • Lee Kelleher 4020 posts 15802 karma points MVP 13x admin c-trib
    Aug 24, 2010 @ 18:25
    Lee Kelleher
    0

    Going back to Dan's original code snippet.  Would this not work?

    <xsl:template match="/">
        <div id="landscape-container">
            <div class="image-group">
                <xsl:for-each select="$currentPage/node [string(data [@alias='umbracoNaviHide']) != '1']">
                    <xsl:variable name="mediaId" select="data [@alias = 'mainImage']"/>
                    <div>
                        <xsl:choose>
                            <xsl:when test="(position() mod 4) = 0">
                                <xsl:attribute name="class">
                                    <xsl:value-of select="string('x d')" />
                                </xsl:attribute>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:attribute name="class">
                                    <xsl:value-of select="string('x')" />
                                </xsl:attribute>
                            </xsl:otherwise>
                        </xsl:choose>
                        <a href="{umbraco.library:NiceUrl(@id)}">LINK</a>
                    </div>
    
                    <xsl:if test="position() mod 4 = 0 and position() != last()">
                        <xsl:text disable-output-escaping="yes"><![CDATA[</div><div class="image-group">]]></xsl:text>
                    </xsl:if>
    
                </xsl:for-each>
            </div>
        </div>
    </xsl:template>

    The IF tests if the position is a modulus of 4 (and not the last node in the node-set) - then it would output the closing DIV and open a new DIV tag (with the 'image-group' class).  I know it's not pure XSLT ... but it generates the required output HTML, and saves you any headache! ;-)

    Cheers, Lee.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Aug 24, 2010 @ 19:26
    Morten Bock
    2

    Yes, that would probably work, but where's the fun in that? ;-)

    It would loose you a bit of the flexibility, like if you for example decided to put a dynamic css class on some of the elements or so. So I tend to avoid the CDATA method, because it creates elements that the XSLT is not aware of.

  • Lee Kelleher 4020 posts 15802 karma points MVP 13x admin c-trib
    Aug 24, 2010 @ 19:39
    Lee Kelleher
    0

    Absolutely, I do agree! Sometimes there is a fine line between the "proper way" and "getting the job done" (quality vs convenience).

Please Sign in or register to post replies

Write your reply to:

Draft