A jQuery Library for SharePoint Web Services (WSS 3.0 and MOSS): Real World Example – Part 2

Cross-posted from EndUserSharePoint.com

Part 1 Part 2 Part 3 Part 4

In my last article, I showed how I used my jQuery Library for SharePoint Web Services to improve data quality by enhancing an out of the box form using the SPRequireUnique, SPDisplayRelatedInfo, and PreSaveAction functions. In this installment, I’ll show you how I created part of the nice dashboard-like page to display the current state of things to each Project Manager using Data View Web Parts (DVWPs). In this article, I won’t be showing any usage of the jQuery Library for SharePoint Web Services, but in a later article, I’ll show you how I use it again to enable easy bulk upload of the project artifacts.

Figure 1: Project Manager’s Dashboard

You’ll need to bear with me a little bit on this one. Because this example uses an actual client site, I’ve needed to doctor up the screenshots quite a bit. Hopefully you’ll still be able to get the general idea. In Figure 1: Project Manager’s Dashboard, you can see the dashboard for the Project Manager. This dashboard has three main components. In this article, I’m going to talk about sections A and B.

The top DVWP shows basic information about the Request (remember that a Request is like a sub-Project). In this first DVWP, I’m just displaying some of the important metadata about the Project and the Request. Since the data comes from items in those two lists, I’m using an AggregateDataSource. If you want to build your applications by using lists like relational tables (ALWAYS a good idea), you’ll need to become familiar with the AggregateDataSource concept.

This code is going to look a little messy, but here’s how you specify an AggregateDataSource:

<DataSources>
    <SharePoint:AggregateDataSource runat="server"  IsSynchronous="" SeparateRoot="true" RootName=""  RowsName="">
   <Sources>
   <SharePoint:SPDataSource  runat="server" DataSourceMode="List" SelectCommand="&amp;lt;View&amp;gt;&amp;lt;/View&amp;gt;"  UseInternalName="True">
   <SelectParameters>
   <WebPartPages:DataFormParameter  ParameterKey="ListName" PropertyName="ParameterValues"  DefaultValue="SDLC Projects"  Name="ListName"></WebPartPages:DataFormParameter>
   </SelectParameters>
   </SharePoint:SPDataSource>
    <SharePoint:SPDataSource runat="server"  DataSourceMode="List"  SelectCommand="&amp;lt;View&amp;gt;&amp;lt;/View&amp;gt;"  UseInternalName="True">
    <SelectParameters>
   <WebPartPages:DataFormParameter  ParameterKey="ListName" PropertyName="ParameterValues"  DefaultValue="SDLC Requests"  Name="ListName"></WebPartPages:DataFormParameter>
    </SelectParameters>
    </SharePoint:SPDataSource>
   </Sources>
   <Aggregate>
   <concat name="data source">
   <datasource name="SDLC_Projects" id="0" Type="SPList"/>
   <datasource name="SDLC_Requests" id="1" Type="SPList"/>
   </concat>
   </Aggregate>
   </SharePoint:AggregateDataSource>
  </DataSources>

When you create a Linked Source in SharePoint Designer (SPD), this is basically the code that you get. IMHO, SPD does a horrible job formatting the code it generates, so one of the first things I usually do is to clean up the formatting of what it creates. Unfortunately, any reformatting that you do of the DataSources will not “stick”; each time you save the page, SPD will mess it all up on you again.

The important sections of the AggregateDataSource are:

  • < SharePoint:AggregateDataSource> – This simply says that you are specifying a DataSource which includes multiple sources.
  • < SharePoint:SPDataSource> – You specify an SPDataSource for each individual source. In this case, the two lists: SDLC Projects and SDLC Requests. For simplicity here, I’m grabbing all of the items from each list (SelectCommand=”&lt;View&gt;&lt;/View&gt;”) but the SelectCommand is where you would specify any CAML you need.
  • <SelectParameters> – For each source, you need to indicate where it is. You do this with <WebPartPages:DataFormParameter>s. Note that I have switched from ListID to ListName. This can be helpful if you want to refer to your lists by their text name rather than their GUIDs. This also makes your code portable, in that SharePoint will just look for a list with the name you’ve specified rather than a specific GUID, which will be different across sites, Site Collections, or Web Applications.
  • <Aggregate> – In this section, you assign working names to the individual DataSources which you then use to refer to them later in your XSL. I typically just use the list name with any spaces replaced with underscores (there can’t be spaces here).

To create the links in section B, which is actually part of the same DVWP as section A, I needed some IIS Server Variable values. Another important “set up” section of the DVWP is the <ParameterBindings> section. Here it is with a few of the garden variety bindings left out.

<ParameterBindings>
  ...
   <ParameterBinding  Name="URL" Location="ServerVariable(URL)"  DefaultValue=""/>
   <ParameterBinding  Name="SERVER_NAME" Location="ServerVariable(SERVER_NAME)"  DefaultValue=""/>
   <ParameterBinding  Name="PATH_INFO" Location="ServerVariable(PATH_INFO)"  DefaultValue=""/>
   <ParameterBinding  Name="ProjectID" Location="QueryString(ProjectID)" DefaultValue=""/>
   <ParameterBinding  Name="RequestID" Location="QueryString(RequestID)"  DefaultValue=""/>
  </ParameterBindings>

Again, this is basically what the code looks like when you use the dialogs to create parameters. (At this point, I just go into Split View and write most of this myself because it’s faster for me.) There are three Server Variables I’m using: URL, SERVER_NAME, and PATH_INFO. You can find full documentation for the available Server Variables on MSDN. I’m also grabbing the values for the ProjectID and RequestID from the Query String. This is how the page “knows” what Project and Request we’re interested in.

OK, so I’ve got the DataSource set up, I’ve got the ParameterBindings set up, now it’s time for the XSL. Here are a few of the key bits.

<Xsl><xsl:stylesheet version="1.0"  exclude-result-prefixes="xsl msxsl ddwrt"  xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"  xmlns:asp="http://schemas.microsoft.com/ASPNET/20"  xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls"  xmlns:ddwrt2="urn:frontpage:internal"><br>
   <xsl:output  method="html" indent="no"/>
   <xsl:param  name="URL" />
   <xsl:param  name="SERVER_NAME" />
   <xsl:param  name="PATH_INFO" />
   <xsl:param  name="ProjectID" />
   <xsl:param  name="RequestID" />

In this top part, I’m just declaring the stylesheet and specifying the xsl:params I built up in the ParameterBindings section. This makes their values available in the XSL as well.

Next comes the initiation template. I don’t actually know what this is really called, but I think of it as kicking off the whole process. It calls my first real working template, SDLC_Requests. SPD by default uses template names like dvt_1, dvt_1.body, etc., but I replace those names with names that match what list or data I’m working with to make it easier to follow.

<xsl:template match="/"  xmlns:asp="http://schemas.microsoft.com/ASPNET/20"  xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"  xmlns:SharePoint="Microsoft.SharePoint.WebControls">
   <xsl:call-template name="SDLC_Requests"/>
  </xsl:template>

In the SDLC_Requests template, I simply grab the item from the SDLC_Requests list I want, and start building the table I want to display. (Think of xsl:templates as being sort of like subroutines.) I create a variable called Rows and select all of the items in the SDLC_Requests list which have a Title (I’ve repurposed the Title column for the RequestID) which matches the values on the Query String. If you remember, in the last article I made sure that the RequestID is unique per item. Next I call the SDLC_Requests.rowview template to generate the table rows.

<xsl:template name="SDLC_Requests">
   <xsl:variable  name="Rows"  select="/dsQueryResponse/SDLC_Requests/Rows/Row[@Title =  $RequestID]"/>
   <table  border="0" width="100%" cellpadding="2"  cellspacing="0">
   <xsl:for-each  select="$Rows">
   <xsl:call-template  name="SDLC_Requests.rowview" />
   </xsl:for-each>
   </table>
  </xsl:template>

The SDLC_Requests.rowview template is where the action is; this is where I output the actual values from the appropriate list items. I won’t show all of the XSL, but here are some of the interesting pieces.

At the top of the SDLC_Requests.rowview template, I set up some xsl:variables. For each of these three variables, I’m grabbing a value from the parent SDLC_Project’s item based on the ProjectID in the SDLC_Requests item’s ProjectID column. (Again, I’ve repurposed the Title column in the SDLC Projects list for the ProjectID.)

<xsl:template name="SDLC_Requests.rowview">
   <xsl:variable name="Methodology"  select="/dsQueryResponse/SDLC_Projects/Rows/Row[@Title =  current()/@ProjectID]/@Methodology"/>
   <xsl:variable name="Applications"  select="/dsQueryResponse/SDLC_Projects/Rows/Row[@Title =  current()/@ProjectID]/@Applications"/>
   <xsl:variable name="BusinessGroup"  select="/dsQueryResponse/SDLC_Projects/Rows/Row[@Title =  current()/@ProjectID]/@Business_x0020_Group"/>

The next part shows how I output the header for the DVWP. I wanted it to look just like the normal page header, so I used the same CSS class. The call to ddwrt:IfNew lets me display the usual New! Icon if the Request was created recently.

<tr>
   <td  style="padding-left:0px;"  colspan="2">
   <xsl:value-of  select="@Request_x0020_Description"/> (<xsl:value-of  select="@Title"/>)
   <xsl:if  test="ddwrt:IfNew(string(@Created))">
   <IMG  SRC="/_layouts/1033/images/new.gif" alt="New" />
   </xsl:if>
   </td>
  </tr>

Next I start outputting the column values for the Request. For each row, I’m using the same CSS classes which are usually used on the DispForm.aspx page. I like to try to keep the formatting consistent across pages. I’m using conditional formatting for the Methodology column so that I can show a message if the value is blank. (A blank value here is a problem because the artifact requirements are driven by what the Methodology and Request Type values are.) I’m only showing a few of the columns here; the rest of the XSL looks pretty similar.

<tr>
   <td  width="25%">
   Request Type
   </td>
   <td >
   <xsl:value-of  select="@Request_x0020_Type"/>
   </td>
  </tr>
  <tr>
   <td  width="25%">
    Methodology
   </td>
   <td >
   <xsl:choose>
    <xsl:when  test="string-length($Methodology) &gt; 0">
    <xsl:value-of  select="$Methodology"/>
   </xsl:when>
   <xsl:otherwise>
   <i>No  methodology specified.</i>
   </xsl:otherwise>
   </xsl:choose>
   </td>
  </tr>


Finally, I output the links in section B. You’ll see that I’m building up rather complicated links so that I can both pass the values I’ll need on the other end as well as be ensured that I’ll be passed back to this page with the needed values for ProjectID and RequestID when I return.

<tr>
   <td  colspan="99">
   <table  style="width: 100%">
   <tr>
   <td >
   <a  href="Lists/SDLC%20Requests/EditForm.aspx?ID={@ID}&amp;amp;Source={$URL}?ProjectID={$ProjectID}%26RequestID={$RequestID}">Edit  the Request</a>
   </td>
   <td >
   <a  href="Default.aspx?Group={ddwrt:UrlEncode(string($BusinessGroup))}">Go  back to <xsl:value-of select="$BusinessGroup"  disable-output-escaping="yes"/> projects</a>
   </td>
   </tr>
   <tr>
   <td >
    <a  href="/sites/CSO/KR/SDLC%20Artifact%20Repository%202010/Forms/AllArtifacts.aspx?RootFolder=%2fsites%2fCSO%2fKR%2fSDLC%20Artifact%20Repository%202010%2f{translate($RequestID,  ':', '-')}">View All Artifacts for this Request</a>
   </td>
   <td >
   <a  href="ArtifactsMatrix2010.aspx?RequestType={@Request_x0020_Type}&amp;amp;Methodology={$Methodology}&amp;amp;ProjectID={$ProjectID}&amp;amp;RequestID={$RequestID}">View  Artifact Requirements</a>
   </td>
   </tr>
   </table>
   </td>
  </tr>
</xsl:template>
</xsl:stylesheet></Xsl>

In the next article, I’ll show what’s going on in the DVWP in section C, followed by what happens behind the scenes when the Project Manager decides to click on one of the Upload links to add artifacts to the repository.