Alpha Selection of List Items in a Data View Web Part (DVWP)

Say you have a list of people (or rooms or products or whatever) where you would like to let the user specify the first letter of the person and then show them all of the people’s names which start with that letter.  Doable, of course, and a nice little recursive XSL template can get you there.  The little screenshot below doesn’t look like much, but it shows an example of this type of alpha listing with the letter C selected.

The Alpha template below takes two parameters:

  • Rows: The nodeset which contains the rows you want to work with (needed to make the right letters links vs. static text)
  • RemainingLetters: The list of ‘remaining’ letters you have to work with.  On first call, this should be ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’, since you still have the whole alphabet to go.

The template is recursive; as long as there’s still work to do, it calls itself again with the remaining letters to work with.  There are a couple of slick bits to this:

  • The xsl:attribute setting of the style bolds the letter if it is the letter the user has chosen
  • If there aren’t any items in the list which start with the letter, then we don’t make the letter a link.  (It’s always annoying to have a link that returns you nothing.)
  • The links simply call the same page with the chosen letter on the Query String (?Letter=X)
<xsl:template name="Alpha">
    <xsl:param name="Rows"/>
    <xsl:param name="RemainingLetters"/>
    <xsl:variable name="ThisLetter" select="substring($RemainingLetters, 1, 1)"/>
  
<td>
        <xsl:attribute name="style">
            <xsl:if test="$ThisLetter = $Letter">
                font-weight:bold;
            </xsl:if>
        </xsl:attribute>
        <xsl:choose>
            <xsl:when test="count(/dsQueryResponse/Rows/Row[starts-with(@Title, $ThisLetter)])">
                <a href="{$URL}?Letter={$ThisLetter}"><xsl:value-of select="$ThisLetter"/></a>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$ThisLetter"/>
            </xsl:otherwise>
        </xsl:choose>
  </td>
    <xsl:if test="string-length($RemainingLetters) &> 1">
        <xsl:call-template name="Alpha">
            <xsl:with-param name="Rows" select="$Rows"/>
            <xsl:with-param name="RemainingLetters" select="substring-after($RemainingLetters, $ThisLetter)"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

You can call the Alpha template like this:

<xsl:call-template name="Alpha">
    <xsl:with-param name="Rows" select="$Rows"/>
    <xsl:with-param name="RemainingLetters" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
</xsl:call-template>

and the row selection looks like this:

<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row[
    starts-with(@Title, $Letter) or
    string-length($Letter) = 0
   ]"/>

Similar Posts

63 Comments

  1. I got this code working, the video was wonderful. I tried adding items to the list after implementing the code and when Hyperlinking to the letter it should be under, it does not show up. Any suggestions.

    1. Chris:

      Glad this was useful! Since the DVWP is working dynamically, I’d check to make sure that the items are checked in or published, whichever applies based on what type of items they are.

      M.

  2. Thanks Marc for the quick reply,

    I tested several things and found out that in fact new items are being added however they need to start with a capital letter. I’ll try using the translate function you mentioned earlier to get it working properly. Again thank you for sharing this.

  3. Hi Marc, great article. I am trying to use this code but I’ve got a scenario where the items may start with an upper or lower case letter. Can you give me a suggestion as to how I would make that work?

    Thank you,
    Marc

    1. Marc:

      You can convert strings to upper or lower case, but there isn’t a nice, tidy function for it. You can use translate like this:

      <xsl:variable name="UColumnName" select="translate(@ColumnName, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/> 

      Come to think of it, that’s a great little template for me to add to my SPXSLT Codeplex Project!

      M.

      1. Hi Marc – Thanks for the great solution. Would you mind show me where to insert the translate script? I am new to XSLT and SharePoint. Thanks.

  4. I am trying to use your well documented solution in a SharePoint 2010 site but am experiencing some difficulty.

    Since SP 2010 defaults to XSLT web parts for data views, I first added an empty DataFormWebPart with a List as the data source. My filter column name is “TermPhrase” (…&Field=TermPhrase) and then added the filters “Letter” & “URL” as seen in the video provided by ValerianCh however I keep getting the following error message in SPD:

    “This Web Part does not have a valid XSLT stylesheet:
    Error: A name was started with an invalid character.”

    I edited the code provided with the List column as follows (copied from http://jeffbreece.com/site/files/alpha.txt, as provided by Jeff):

    <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row[
        starts-with(@TermPhrase $Letter) or
        string-length($Letter) = 0
       ]"/>
    
       
    <xsl:call-template name="Alpha">
        <xsl:with-param name="Rows" select="$Rows"/>
        <xsl:with-param name="RemainingLetters" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
    </xsl:call-template>
    
    
    <xsl:template name="Alpha">
        <xsl:param name="Rows"/>
        <xsl:param name="RemainingLetters"/>
        <xsl:variable name="ThisLetter" select="substring($RemainingLetters, 1, 1)"/>
      
    <td>
            <xsl:attribute name="style">
                <xsl:if test="$ThisLetter = $Letter">
                    font-weight:bold;
                </xsl:if>
            </xsl:attribute>
            <xsl:choose>
                <xsl:when test="count(/dsQueryResponse/Rows/Row[starts-with(@TermPhrase, $ThisLetter)])">
                    <a href="{$URL}?Letter={$ThisLetter}"><xsl:value-of select="$ThisLetter"/></a>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$ThisLetter"/>
                </xsl:otherwise>
            </xsl:choose>
      </td>
        <xsl:if test="string-length($RemainingLetters) &> 1">
            <xsl:call-template name="Alpha">
                <xsl:with-param name="Rows" select="$Rows"/>
                <xsl:with-param name="RemainingLetters" select="substring-after($RemainingLetters, $ThisLetter)"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    
    1. Jeff:

      Sorry for the trouble you had posting code; WordPress makes it hard.

      I see a couple of things that look like problems:
      * You need a comma in this line

      starts-with(@TermPhrase, $Letter) or 

      * This line

      <xsl:if test="string-length($RemainingLetters) &> 1">

      should be

      <xsl:if test="string-length($RemainingLetters) &gt; 1">

      Either one of these things could be simply an artifact of the copy/paste, but fix them and see if you still have an error. If you do, then strip out the call to the Alpha template and the template itself and build things back up again.

      M.

      p.s. I removed your extra comments and added the code into your original.

    1. Anita:

      Not without modification. As you can see form the XSL in the template, the example I show is using the Title column. You’d need to alter the XSL to parse out the name of the person or group from whatever column you wanted to use instead.

      M.

    1. Scott:

      Sure. Just change the conditions on the definition of the $Rows variable by removing
      “or string-length($Letter) = 0”. That condition is why it shows all items if no letter is selected.

      M.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.