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

Cross-posted from EndUserSharePoint.com

Part 1 Part 2 Part 3 Part 4

Please forgive me; it’s been over one month since my last confession 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 and B below – on the dashboard worked by using an AggregateDataSource, values passed in on the Query String, and complex links to other functionality. In this article, I’ll talk about the DVWP in section C.

Section C is really the “meat” of the page. This DVWP uses 8 (yes, that’s eight, ocho, huit) different lists for its DataSources. While this may seem excessive, it allowed us to have lists that we treated purely as relational tables from a content management perspective. While we didn’t get too granular with the permissions on these lists, by having them separated the way we did, we had that option going forward.

I won’t go into all of the details of what was stored in each list, but they follow all relational rules. If you look through the view above, hopefully you can see how things might break out. (Post a comment if you are interested in these details: maybe another article!)

There are a couple nice things going on in this DVWP which are probably worth calling out, though:

  • The little plus and its partner minus signs, and
  • The “button”

The Plus and Minus Signs

If you look closely at the first image above, you’ll see that there’s a little image to the right of the Project Charter Artifact Type. Rather than showing all of the artifacts that fulfill a specific requirement, we decided to hide them all, allowing the user to “open” the list sections if they chose to. This makes the DVWP a dashboard (when not showing the details) *and* a locus for activities the user might need to undertake (when showing the details).

I find that a dashboard that is just a dashboard gets far less visibility than one that has the business process embedded in it. This way, the people doing the work see the current state of things on a regular basis as well as those who might be monitoring things. This has been one of my tenets for effective knowledge management for years: embed everything you can in the business process.

In the image below, you can see what the DVWP looks like after clicking on the image. There are links for each artifact (in this view, just one artifact) to Open or View in the Actions column.

This is really a pretty simple thing to do, but may be beyond the capability of many DVWP builders because it isn’t possible without diving into the XSL. Here’s how I made it happen:

First, if there are artifacts in place for the requirement, I output the image. The IMG gets a unique ID formed by concatenating the string “PAimg_” (“PA” is short for Project Artifact) and the current item’s position in the rowset. I also set the onmouseover event to change the cursor to a hand and the onclick event to call the showArtifacts() JavaScript function (see below).

<img alt="" style="vertical-align:middle" id="PAimg_{position()}" onmouseover="this.style.cursor='hand';" onclick="showArtifacts(this);" src="_layouts/images/plus.gif"/>

Next, when I output the TABLE containing the artifact details, I wrap it in a DIV. The DIV has a unique ID formed by concatenating the string “PARows_” and the current item’s position in the rowset. I also set the display:none so that, by default, the DIV won’t be visible.

<div id="PArows_{position()}" style="display:none">
  <table cellpadding="0" cellspacing="0">
    <tr valign="top">
      <th nowrap="">Actions</th>
      <th nowrap="">Type</th>
      <th nowrap="">Filename</th>
      <th nowrap="">Version</th>
    </tr>
    <xsl:for-each select="$ArtifactList">
      <xsl:call-template/>
    </xsl:for-each>
  </table>
</div>

Finally, the JavaScript. Those of you who have been following along with these articles may ask “Why not jQuery?” Well, this is such a simple little function that there really isn’t any need to incur the overhead for jQuery. If I already had jQuery loaded in the page for something more complex, I would certainly use jQuery selectors instead. This is a good example of a case where jQuery is *not* necessarily a good idea, as I discussed in several posts over on my blog.

The net-net of this function is that it simply toggles the display of the DIV and the and signs.

<script language="javascript">
  function showArtifacts(obj) {
    thisId = obj.id.substr(obj.id.indexOf("_")+1);
    thisPA = document.getElementById("PArows_"+thisId);
    if(obj.src.indexOf("plus.gif") > 0) {
      obj.src = "_layouts/images/minus.gif";
      thisPA.style.display = "block";
    } else {
      obj.src = "_layouts/images/plus.gif";
      thisPA.style.display = "none";
  }
}
</script>

The Upload “Button”

It’s not really a button, but just a little image I built to add a little graphic-ness (graphic-icity?) to the page. We wanted to make it clear that this was where you clicked to add artifacts. (Yes, a few people were confused by the word Upload.) Clicking on the image passes the context for the row you’re clicking on as well as some parameters on the Query String that makes things work smoothly.

<img alt="Upload" src="/sites/CSO/KR/PublishingImages/Upload.png"/><a href="/sites/CSO/KR/_layouts/Upload.aspx?List=%7B41BBE5C5%2D5321%2D4D07%2D8EFC%2D10B064F85E6E%7D&amp;RootFolder=%2Fsites%2FCSO%2FKR%2FSDLC%20Artifact%20Repository%202010%2F{translate($RequestID, ':', '-')}&amp;MultipleUpload=1&amp;Source=http://{$SERVER_NAME}{ddwrt:UrlDirName(string($PATH_INFO))}/SDLC%20Artifact%20Repository%202010/Forms/EditFormBulk.aspx?RootFolder=%2Fsites%2FCSO%2FKR%2FSDLC%20Artifact%20Repository%202010%2F{translate($RequestID, ':', '-')}%26ProjectInfo={$ProjectID}|{$RequestID}|{@Artifact_x0020_Name}|{$URL}">Upload</a>

That looks pretty complicated, so let me break it down a little. We have to do a little fancy footwork to pass the values we need to make this work.

First, the image itself. Simple enough:

<img alt="Upload" src="/sites/CSO/KR/PublishingImages/Upload.png"/>

Next, the link. We decided to *always* send the user to the multiple file upload page. In many cases they will be uploading multiple artifacts anyway, so why have them deal with two different processes? (This never really makes sense to me in the basic SharePoint functionality, anyway.) The way you can make this happen is to have the link go to Upload.aspx with the MultipleUpload=1 Query String parameter. We also need to pass the GUID for the list with the List Query String parameter, and the RootFolder. Here, we’re putting the artifacts for each project into a unique folder which is named based on the project’s RequestID (with the colons replaced with dashes because folder names can’t contain colons). I’ve added carriage returns below to make this [hopefully] more readable:

href="/sites/CSO/KR/_layouts/Upload.aspx
?List=%7B41BBE5C5%2D5321%2D4D07%2D8EFC%2D10B064F85E6E%7D
&amp;RootFolder=%2Fsites%2FCSO%2FKR%2FSDLC%20Artifact%20Repository%202010%2F{translate($RequestID, ':', '-')}
&amp;MultipleUpload=1

Next, I needed to provide the context I’d need on the customized EditFormBulk.aspx page. By default, when you upload multiple documents, you’re just sent back from whence you came with the metadata for each document unset. Not a good thing, IMHO, as it requires the user to remember to go back in to set everything. This is definitely a place where things fall through the cracks.

So here I’m going to pass EditFormBulk.aspx (my customized metadata-setting page) as the “Source”, along with some values I need on that page to make things work well. First, the Source page itself (not really the Source, but that’s where the user will be redirected from Upload.aspx), then the RootFolder where the documents will have ended up, then a Query String parameter I called ProjectInfo. ProjectInfo is actually a compound value built up from the ProjectID, the RequestID, the ArtifactName, and the URL with the vertical bar (|) as a separator. Because I’m layering things in pretty deeply, I needed to combine these values and parse them out on the EditFormBulk.aspx page.

&amp;Source=http://{$SERVER_NAME}{ddwrt:UrlDirName(string($PATH_INFO))}/SDLC%20Artifact%20Repository%202010/Forms/EditFormBulk.aspx?RootFolder=%2Fsites%2FCSO%2FKR%2FSDLC%20Artifact%20Repository%202010%2F{translate($RequestID, ':', '-')}%26ProjectInfo={$ProjectID}|{$RequestID}|{@Artifact_x0020_Name}|{$URL}">Upload</a>

All of this ends up looking something like this:

/sites/CSO/KR/_layouts/Upload.aspx?List=%7B41BBE5C5%2D5321%2D4D07%2D8EFC%2D10B064F85E6E%7D&RootFolder=%2Fsites%2FCSO%2FKR%2FSDLC%20Artifact%20Repository%202010%2FDUMMYRequestID&MultipleUpload=1&Source=http://collaborate/sites/CSO/KR/SDLC%20Artifact%20Repository%202010/Forms/EditFormBulk.aspx?RootFolder=%2Fsites%2FCSO%2FKR%2FSDLC%20Artifact%20Repository%202010%2FDUMMYRequestID%26ProjectInfo=1234567890|DUMMYRequestID|Project%20Charter|/sites/CSO/KR/ViewRequest.aspx

What’s Next?

I had to do quite a bunch of complicated stuff to make this page look and work well, but it really provides a great springboard for user activities as well as an easy dashboard view of the project itself. The page does a lot, but looks pretty simple. It takes a few seconds to load, but no more, even given all of the complexity in the DVWPs.

In my next article, I’ll show what the multiple document metadata entry page (EditFormBulk.aspx) looks like and how it works. Teaser: Yes, it uses jQuery and my jQuery Library for SharePoint Web Services to get its jobs done quite extensively, specifically the Lists Web Service’s operations GetListItems, UpdateListItems, and CheckInFile.

Similar Posts

21 Comments

  1. Hi,

    I guess you’re using the SPD Linked Sources to connect the lists? Do you know if there is a way to filter the list based on colums in all lists? Just got it to work with the first column…

    Do you have a quick way to get rid of those “extra headers” on the joined lists or do you have to update the code directly?

    Btw, published a new version of my bulk site updater (Still very ugly, but works) http://spmsaui.codeplex.com/ based on your jQuery Library for SharePoint Web Services.

    1. I do pretty much everything by just writing the XSL at this point. I’ve been doing this for too long to let the dialogs slow me down. ;-)

      “Joining” in a DVWP is really a misnomer, as I’ve written about before. All that really happens is the SharePoint Designer builds the XSL templates such that the rowsets are filtered appropriately. This can be very inefficient if you let SPD take care of it; in my example here, my code is very skinny, even with 8 lists in play.

      M.

      1. Should it work the same in SP 2010? I tried something like the link below. I get to the source page only if I set the source string to end after domain. I want to end up on bulkedit.aspx with a parameter.

        https://[domain]/%5Bsite%5D/_layouts/upload.aspx?List=%7B99E64ECA%2DF496%2D415A%2D9FEB%2D3A5765D522AA%7D&MultipleUpload=1&RootFolder=%2F%5Bsite%5D%2FShared%20Documents%2FDOG&Source=https%3A%2F%2F%5Bdomain%5D%2F%5Bsite%5D%2Fsitepages%2Fbulkedit.aspx%3FFORUM%3DDOG

  2. Hi Marc,

    another great series. I was wondering, is it possible to make the upload link generic i.e., not specific to the list ID?

    Cheers,

    Katie

  3. The idea is that if the dvwp is part of a page layout it should be generic to go to a given list on the current site, similar to using ListName instead of ListID. I guess that you wouldn’t need this if the toolbar option would work on a dvwp. Going to trouble shoot that tomorrow. I found a tip to try.

    1. Oh, OK, I see what you mean. No, the List Query String parameter must contain the ListID GUID. However, you can determine that GUID based on the list name in your DVWP so that your code is still portable across sites or environments. You could determine the ListID using the Lists Web Service, GetList operation using SPServices.

      M.

  4. Hii All,
    Am having a req to upload the files or documents whatever the default Sharepoint upload.aspx is doing but which i need to call it from TopNavigationMenuV4 ,not from the default Upload menu, it will be there in TopNavigationMenuV4 which i did the customization according to the requirement .
    Kindly help me how to proceed !!!!!

    Thanks in Advance
    Praveen

      1. Hii Marc,

        Thanks for quick response.

        I want to make the “Add Document” (upload.aspx Functionality)to Place in the Top navigation Header V4 (i.e.,beside to Search Text Box) according to my requiremnt.
        Can u guide me how to make it possible and that once am clicking on the some “XX” Doc Lib the same Upload functionality has to happen for “N” Number Doc Lib .

        ABC Doc Lib————>Single “Add Document”
        BCA Doc Lib————->Single”Add Document”




        XYZ Doc Lib———–>Single”Add Document” on Top navigation Header V4

        Thanks in Advance !!!!

        Cheers !!!
        Praveen

        1. Praveen:

          I’m still not quite sure I understand exactly what you are trying to do. Again, it just sounds like you need to add a link to upload documents in the top of the page. If you need it to be a dynamically populated dropdown, then you could use a DVWP in the master page (DataSourceMode=”CrossList”), adding an option per Document Library. Or you could build a custom control or Web Part. It depends on your overall architecture.

          M.

  5. Hii Marc,

    Many Thanks for the quick response which am hardly looking for the solution for the past couple of days and i want to tell you taht was recently started working on Sharepoint .

    Yes, I Need to Add a link(Name Called “Upload” what our “Add Document” will do to upload documents in the top of the page as per the requirement
    Yes your are correct and my idea is also that to build a custom user control to be called by a webpart.

    Can you please post me with the lines of coding which i got strucked with what am having is not working.

    Thanks
    Praveen

Leave a Reply to Marc Cancel 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.