1,525 articles and 10,948 comments as of Sunday, May 2nd, 2010

Wednesday, December 9, 2009

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

Marc D AndersonGuest Author: Marc D. Anderson
http://mdasblog.wordpress.com

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.

jQuery Library for Web Services
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.

jQuery Library for Web ServicesThe 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  class="ms-webpartpagedescription" 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  class="ms-formlabel" width="25%">
   Request Type
   </td>
   <td  class="ms-formbody">
   <xsl:value-of  select="@Request_x0020_Type"/>
   </td>
  </tr>
  <tr>
   <td  class="ms-formlabel" width="25%">
    Methodology
   </td>
   <td  class="ms-formbody">
   <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>

jQuery Library for Web Services

jQuery Library for Web ServicesFinally, 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  class="actiontext">
   <a  href="Lists/SDLC%20Requests/EditForm.aspx?ID={@ID}&amp;amp;Source={$URL}?ProjectID={$ProjectID}%26RequestID={$RequestID}">Edit  the Request</a>
   </td>
   <td  class="actiontext">
   <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  class="actiontext">
    <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  class="actiontext">
   <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>
<p>  </xsl:template></p>
<p></xsl:stylesheet></Xsl>

jQuery Library for Web ServicesIn 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.

Marc D AndersonGuest Author: Marc D. Anderson
http://mdasblog.wordpress.com

Marc D. Anderson is a Co-Founder and the President of Sympraxis Consulting LLC, based in Newton, MA.  He has over 25 years of experience as a technology consultant and line manager across a wide spectrum of industries and organizational sizes.  Marc has done extensive consulting on knowledge management and collaboration and what makes them actually work in practice.  Marc is a very frequent “answerer” on the MSDN SharePoint – Design and Customization forum.

 

Please Join the Discussion

6 Responses to “A jQuery Library for SharePoint Web Services (WSS 3.0 and MOSS): Real World Example – Part 2”
  1. Jeff says:

    can be very powerful indeed.

    I was using that today to link 3 lists while using the XSLT functions substring-before() and substring-after() directly on the JOIN SPD built for me in order to doctor up the text and make parent/child records line up. I’ve used it for output formatting but never JOIN which was fun.

    My alternative was a simple SPD workflow on one side of the lists. But the data duplication and delay were not very appealing here.

    Nice work! Keep the great blog posts comin’

    Like? Thumb up 0 Thumb down 0

  2. Hey there,

    I am trying to match two Title values from two linked data sources.

    Something like:

    test=”/dsQueryResponse/Ranking/Rows/Row[@PostTitle= current()/@Title ]/@Ranking

    It is not working … it seems like they have the same values but there is something that cannot match… works for ids perfectly though! Any help would be appreciated

    thanks,

    Iryna

    Like? Thumb up 0 Thumb down 0

Trackbacks

Check out what others are saying about this post...
  1. [...] A jQuery Library for SharePoint Web Services (WSS 3.0 and MOSS): Real World Example – Part 2 [...]

    Like? Thumb up 0 Thumb down 0

  2. [...] forgive me; it’s been over one month since my last article in this series.  When last we spoke, I left you with the details of how one of the Data View Web Parts (DVWPs) – sections A  [...]

    Like? Thumb up 0 Thumb down 0

  3. jQuery Library for SharePoint Web Services…

    ich bin auf eine sehr interessante Artikel-Serie von Marc D. Anderson gestoßen, die ich hier gern verlinken…

    Like? Thumb up 0 Thumb down 0




Notify me of comments to this article:


Speak and you will be heard.

We check comments hourly.
If you want a pic to show with your comment, go get a gravatar!