Copied to clipboard

Flag this post as spam?

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


  • Rob Watkins 369 posts 701 karma points
    Aug 11, 2011 @ 14:50
    Rob Watkins
    0

    Results filtering problem

    I'm having conceptual issues with a filtering problem; the actual macro is huge so I'm going to try to post a cut down version.

    I am using PDCalendar, which returns a nodeset similar to this:

    <pdcalendar>
        <node date="2011-08-19">
            <event id="2106"/>
            <event id="2107"/>
        </node>
        <node date="2011-08-20">
            <event id="2108"/>
        </node>
        <node date="2011-08-21">
            <event id="2106"/>
        </node>
    </pdcalendar>

    The event IDs are document IDs. Node that the last node contains an event with an ID already seen - this is a recurring event.

    What I am doing is creating a list of all events for a date range, and then, this is the bit that is throwing a spanner in my later works, filtering them by various properties on the page:

    <!-- Get all dates that have events -->
    <xsl:for-each select="$pdcalendar/node[count(event) &gt; 0]">
    
        <!-- Get the date this event occurs on (important for recurretn events -->
        <xsl:variable name="currentDate" select="@date"/>
    
        <!-- Just do one display line per event  - it is not broken down into groups of dates -->
        <xsl:for-each select="event">
            <xsl:variable name="eventDocument" select="umbraco.library:GetXmlNodeById(@id)"/>
    
            <xsl:variable name="searchValue">
                <!-- Concatentate some useful text fields from $eventDocument here -->
            </xsl:variable>
    
            <!-- Display events matching the filter conditions -->
            <xsl:if test="$query_string_filter = '' or regex:test($searchValue, $query_string_filter, 'i')">
                <xsl:call-template name="displayEvent">
                    <xsl:with-param name="currentDate" select="$currentDate"/>
                    <xsl:with-param name="event" select="$eventDocument"/>
                </xsl:call-template>          
            </xsl:if>     
        </xsl:for-each>        

    Now, this all works fine (any typos are from me simplifying for this post).

    What the client wants now is a "Load more..." AJAX thing that gets blocks of events, so I want to generate all events for the year - easy, then get them in blocks of 5.

    Unfortunately, because of the xsl:if filtering, I never have a node-set containing the final list of nodes to generate blocks using position(). And I can't simply add the filtering to the for-each (as far as I'm aware) because I need to go off and get the document nodes.

    I also can't use the document nodes as the main working node-set because I need the dates returned by the calendar for recurrent events.

    So, what is my next move? Is there a way to make this work? Or is there a completely different technique I need to use that I'm not seeing? :o)

  • Rob Watkins 369 posts 701 karma points
    Aug 11, 2011 @ 15:30
    Rob Watkins
    0

    Well, I have worked out that I can do this, at a pinch, in place of the: <xsl:for-eachselect="event">

    <xsl:for-each select="event[($filter = '' or regex:test(concat(umbraco.library:GetXmlNodeById(@id)/@nodeName, ' ', umbraco.library:GetXmlNodeById(@id)/description), $filter, 'i'))]">

    ...but that's DISGUSTING, and will be even more so with more search fields, there HAS to be a better way than that.


  • Rob Watkins 369 posts 701 karma points
    Aug 11, 2011 @ 15:44
    Rob Watkins
    0

    Oh tits, that doesn't help that much either, as I need to get the combined position of the event within a date, whereas position() will just return the position of the current event WITHIN THE CURRENT DATE.

    Please help, off on holiday soon :o)

  • Rob Watkins 369 posts 701 karma points
    Aug 11, 2011 @ 16:21
    Rob Watkins
    0

    Hmm, okay, have a hacky answer. It's not very XSLT, so I'd love a "correct" way of doing this if there is one, but it's a lot more maintainable than sticking everything in the predicate.

    It relies on the fact that the displayEvent template returns a single node/tag - in my case, an LI.

    You can wrap both for-each loops, complete with filtering logic in an xsl:variable tag, then simply select out the LIs you want for the selected page from that, by using msxml:node-set() to make it iterable:

    <xsl:for-each select="msxml:node-set($final)/li[((position() - 1) &gt;= $blockIndex * $blockSize) and ((position() - 1) &lt; ($blockIndex + 1) * $blockSize)]">
       <xsl:copy-of select="."/>
    </xsl:for-each>

    I don't really like it, but it's the best I've come up with so far and will enable me to go on holiday with a happy client :o)

    In fact, you don't need the display template to return a single node - you can wrap in with a tag of your choosing and then just use the final select that does the paging to remove it before output.

Please Sign in or register to post replies

Write your reply to:

Draft