Category Archives: jQuery and SharePoint

Overcome Annoying Problem with Relative Urls in SharePoint Quick Launch

I wanted to add a link to the quick launch navigation the other day and SharePoint told me:

image

Pure text version of that is:

Ensure that the URL is valid and begins with either a valid character (a number sign (#) or forward slash (/)) or a valid supported protocol (for example, ‘http://’, ‘https://’, ‘file://’, ‘ftp://’, ‘mailto:’, ‘news:’).

“Blech and pox!” I said.

A workaround to this is to use JavaScript to find a known link in the quick launch and override its behavior.

To test this, add a new link to your test site thusly:

image

I used jQuery.  To solve it, get some JavaScript and jQuery onto the page using your favorite technique and with a line of code like this:

 

$(document).ready( function () {

    $("a:contains('Test URL replacement')").click(function () { alert("changed click behavior!"); return false;});

});

And Bob’s your uncle.

The jQuery selector finds every <a> tag that has “Test URL replacement” in its name.  You may want to find-tune that depending on your link and such.

The .click(function() overrides whatever SharePoint would have done when the user clicked.  Make sure you “return false” or else it will do your stuff and then try to the href thing too, which is almost certainly not your goal.

This was done and test in a SharePoint online environment but should work well in 2010 and earlier too.

</end>

undefinedSubscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

Quick and Simple: Solve “Invalid URL Parameter” problem with UpdateListItems in lists.asmx

When working with UpdateListItems via lists.asmx, it’s easy to generate the error:

Invalid URL Parameter.

The URL provided contains an invalid Command or Value. Please check the URL again.

You can get this error when you forget to include ID in the the list of fields to update.  This, like a lot of these SP web services, is a bit counterintuitive since you need to include the ID in the ID attribute of the <Method> element.  And you’re not updated ID and probably never want to in the first place.

This SOAP envelope works:

<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'>
  <soapenv:Body>                      
    <UpdateListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'>                     
      <listName>{C712E2EA-54E1-47AD-9D99-1848C7773E2F}</listName>                     
        <updates>                     
         <Batch OnError="Continue">
          <Method ID="1" Cmd="Update">
            <Field Name="CooperativeLock">locked!</Field>
            <Field Name="ID">1</Field>
          </Method>
        </Batch>                     
        </updates>                
      </UpdateListItems>             
  </soapenv:Body>         
</soapenv:Envelope>

If you strip out the ID field reference then you’ll get the annoying “Invalid URL parameter” message.

</end>

undefinedSubscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

 

Poor Man’s Caching in JavaScript

[TL;DR version: use cookies to store the results of async calls; render the results of past async calls immediately and then validate them after page-load.]

I’ve been working on SharePoint intranet site for a client that features, among other things, a stylized secondary navigation whose menu options are managed via a regular old custom list.  The idea is that the client gets to control “their” site’s menu without affecting or being affected by the global navigation put out by IT.

(there is something incredibly subversive about adding a CEWP that points to an HTML file that loads some CSS and JS to fundamentally alter almost everything about a site’s behavior… but that’s for another post)

The code for this pretty simple:

The sore spot here is that every time anyone hits one of the site’s pages, that user’s web browser is reaching out to get items from the list.  Once dev is complete and testing has proven things to be stable and complete, this call is unnecessary more than 99% of the time since the menu rarely changes.  It also has a weird UI affect which is common in this brave new world of hyper-ajaxy web sites – the page renders and only then does the menu render.  It’s jittery and distracting in my view.  And jittery. So, caching. 

I modified the logic thusly:

  • Look for a cookie in the browser that contains the menu as I last read it
    • If found, render it immediately.  Don’t wait for the page to finish loading.  (You need to make sure your HTML is strategically placed here, but it’s not hard to do).
  • Wait for the page to finish loading and make an async call to load up menu items from a list using REST or lists.asmx or whatever
  • Compare what I got against the cookie
    • If it matches, STOP
    • Otherwise, using jQuery, dynamically populate a bunch if <li>’s in a <ul>
  • Use CSS to do all the formatting
  • Profit!

Some of you are going to say, “hey! there’s no real caching going on here since you’re reading the menu anyway every single time.”  And you’re right – I’m not giving the server any kind of break.  But because the call is async and happens after the page’s initial HTML payload fully renders, it “feels” more responsive to the user.  The menu renders pretty much as the page draws.  If the menu happens to the change, the user is subjected to a jittery re-draw of the menu, but only that one time.

There are some ways to make this caching more effective and help out the server at the same time:

  • Put in a rule that the “cookie cache” is valid for a minimum of 24 hours or some other timeframe. As long as there is no expired cookie, use the cookie’s menu snapshot and never hit the server.

Well … that’s all that come to mind right now :). 

If anyone has any clever ideas here I’d love to know them.

And lastly – this technique can be used for other stuff.  This client’s page has a number of data-driven things on various pages, many of them changing relatively rarely (like once a week or once a month).  If you target specific areas of functionality, you can give a more responsive UI by pulling content from the local cookie store and rendering immediately.  It feels faster to the user even if you’re not saving the server any cycles.  You can save the server cycles by deciding on some conditions and triggers to invalidate this local cookie cache.  That’s all situational and artsy stuff and really the most fun :). 

</end>

undefinedSubscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

XSLT and jQuery Samples

I have been doing a lot of of XSLT and jQuery and thought I’d share a few snippets that others may find useful in future.

Example 1: Emit simple JavaScript / jQuery in XSLT:

<xsl:template match="something" xml:space="preserve">

  <!– Blank out the query friendly filters hidden field –>
  <script type="text/javascript">
    $(document).ready(function(){
      $("#QueryFriendlyFilters").val("empty");
    });
  </script>

</xsl:template>

That bit emits some JavaScript that waits for the page to finish loading (because of the $(document).ready(…)) and then sets the value of a hidden field named QueryFriendlyFilters to the literal value “empty”.

Example 2: Use <xsl:if> to check “greater than”,  “less than”, etc.

<xsl:template match="something" xml:space="preserve">

  <div id="fdcAllFilters">
 
    <xsl:if test="@Count>0">
      <span class="fdcFilterLabel">Current filters:</span>
    </xsl:if>

    <!– more stuff happens here. –>

</xsl:template>

The above snippet checks to see if an attribute named “Count” of the “something” element is greater than zero.  The XML behind this would be something like:”

<something Count=”5” />

Example 3: Iterate through all elements, interspersing jQuery calls.

<!– Iterate through all the filters and display the correct  links. –>
<xsl:for-each select="UserFilter">

  <a class="FilterHref" href="javascript:mySubmitPage(‘RemoveUserFilter’,'{@ID}’)">[X]</a>

  <span class="fdcFilterLabel"><xsl:value-of select="@FilterValue"/></span>

  <script type="text/javascript">

    $(document).ready(function(){
        <xsl:text><![CDATA[$("#QueryFriendlyFilters").val( ($("#QueryFriendlyFilters").val() + " ]]></xsl:text>\"<xsl:value-of select="@FilterValue"/>\"<xsl:text><![CDATA["));]]></xsl:text>
    });

  </script>

</xsl:for-each>

The above snippet is the most complex and there may be easier ways to do it.

The XML behind this looks roughly like this:

<UserFilter ID=”123” FilterValue=”xyzzy” />

This snippet is iterating through <UserFilter> nodes. 

It first emits an anchor tag that when clicked invokes a JavaScript function that is already on the page, “mySubmitPage” and passes the value of an attribute on the <UserFilter> node named “ID”. 

It then emits some jQuery that waits for the page to load.  That jQuery updates a hidden field named “QueryFriendlyFilters” by adding the value of the FilterValue attribute.  Note all the crazy <xsl:text> and <![CDATA[ … ]]> stuff.

That’s it, hope it helps!

</end>

Subscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

Lists.asmx, GetListItems and Folders

I was doing some research for someone today around the list.asmx web service provided as part of SharePoint 2010 (and earlier).  She was able to get the list items at the root folder (including the names of sub-folders), but couldn’t get items in sub-folders.  I did some looking around on the internets and it’s a surprisingly common question.  Yet, I couldn’t get a good answer to the simple question, “if I know the folder, how do I get the items in the folder?”  To be honest, I didn’t try all that hard since I’ve wanted to figure this one out on my own for a while Smile.

To set this up, I created a site named “Blogging Scenarios” and a custom list named “Custom List with Sub Folders”.  I then created folders named:

  • Year 2005
  • Year 2006
  • Year 2007

I added a few items to the folder “Year 2006”.  This is what it looks like:

image

My friend isn’t writing C# code but rather using Java, so the SOAP envelope was what she really needed.  To get that, I wrote a bit of jQuery and then used fiddler to get the actual HTTP conversation.

Here’s the relevant jQuery (I copied the code down below if you want to copy/paste):

image

They first key is to include both a <queryOptions> and <QueryOptions> node.  The second key is that the <Folder> node is a URL to which the client has access.

There may be other ways to get this, but this worked well for me when using jQuery.

Here is the SOAP envelope for the above:

<soapenv:Envelope xmlns:soapenv=’http://schemas.xmlsoap.org/soap/envelope/’>                
  <soapenv:Body>
    <GetListItems xmlns=’
http://schemas.microsoft.com/sharepoint/soap/’>
      <listName>Custom List with Sub Folders</listName>
      <viewFields>  
        <ViewFields>
          <FieldRef Name=’Title’ />
          <FieldRef Name=’EncodedAbsUrl’ />
        </ViewFields>
      </viewFields>
      <queryOptions>
        <QueryOptions>
          <Folder>
http://demoserver1/Blogging Scenarios/lists/Custom List with Sub Folders/Year 2006</Folder>
        </QueryOptions>
      </queryOptions>
   
</GetListItems>
  </soapenv:Body>
</soapenv:Envelope>

A lot of examples and discussion around this led me to believe that all I need was <QueryOptions> and specify a folder name.  For me, I need to both wrap it inside <queryOptions> as well as specify a fully qualified URL for the <Folder> node.

Here’s the jQuery AJAX setup:

$(document).ready(function() {
       var soapEnv =
           "<soapenv:Envelope xmlns:soapenv=’http://schemas.xmlsoap.org/soap/envelope/’> \
               <soapenv:Body> \
                    <GetListItems xmlns=’http://schemas.microsoft.com/sharepoint/soap/’> \
                       <listName>Custom List with Sub Folders</listName> \
                       <viewFields> \
                           <ViewFields> \
                              <FieldRef Name=’Title’ /> \
                              <FieldRef Name=’EncodedAbsUrl’ /> \
                          </ViewFields> \
                       </viewFields> \
                       <queryOptions> \
                         <QueryOptions> \
                           <Folder>http://demoserver1/Blogging Scenarios/lists/Custom List with Sub Folders/Year 2006</Folder> \
                         </QueryOptions> \
                       </queryOptions> \
                   </GetListItems> \
               </soapenv:Body> \
           </soapenv:Envelope>";

</end>

Subscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

Lists.asmx, GetList and “Value cannot be null”

I discovered today that the GetList() method in lists.asmx web service has to be called very carefully or it’s prone to throw a mysterious “Value cannot be null” exception (and that’s assuming you can get past the even worse generic error message, “Exception of type ‘Microsoft.SharePoint.SoapServer.SoapServerException’ was thrown.”)  Specifically, I found that you can’t provide any kind of prefix on the GetList method.  The following jQuery snippet illustrates the point:

image

If you do that, the web service responds with “Value cannot be null” as per this fiddler-provided HTTP transcript:

<?xml version="1.0" encoding="utf-8"?>
  <soap:Envelope
     xmlns:soap="
http://schemas.xmlsoap.org/soap/envelope/"    
     xmlns:xsi=”
http://www.w3.org/2001/XMLSchema-instance
     xmlns:xsd="
http://www.w3.org/2001/XMLSchema">

  <soap:Body>
    <soap:Fault>
      <faultcode>soap:Server</faultcode>
      <faultstring>
        Exception of type ‘Microsoft.SharePoint.SoapServer.SoapServerException’ was thrown.
      </faultstring>
      <detail>
        <errorstring xmlns="
http://schemas.microsoft.com/sharepoint/soap/">
Value cannot be null.
        </errorstring>
      </detail>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

Of course, you probably wouldn’t add that “s0” prefix on your own, but some tools are prone to do it (like Eclipse).

This is all the more confusing / frustrating because other methods tolerate prefixes.  For instance, the GetListCollection method doesn’t mind if it’s been prefixed, even with nonsense prefixes like “xyzzy”:

image

This “value cannot be null” seems fairly common with lists.asmx so hopefully this will help someone out in future.

</end>

Subscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

Endlessly Nesting <div> Tags and jQuery

This seems like such an oddball topic, I’m not sure it’s really worth blogging about, but that’s never stopped me before, so here we go Smile

I’m working out on a project where I’m pulling some data from a search, packaging it up into an XML message and then that XML is ultimately transformed into HTML via XSLT.  There’s a lot of jQuery involved, one bit of which implements some tabbing functionality.  When you click on a tab (really, a <div>), jQuery invokes .hide() and .show() on various divs (the initial page load downloads all the content so there are no postbacks in this case).

A bunch of hours ago, the tab switching logic started to behave erratically and it wouldn’t show one of my tabs.  I ultimately tracked it down to the fact that internet explorer (at least) thought that the <div> tags nested far, far deeper than intended.The developer toolbar would show:

-<div id=”Tab1Content”>
  -<div>
    -<div>
      -<div id=”Tab2Content”>
        -<div>
           …………………………
                   </div>  <—finally showing it was closed all the way down here!

So, if I did a $(“#Tab1Content”).hide(), I’d also hide Tab2 and I could never show Tab2 if I didn’t also show Tab1.  I copied and pasted the code up into visual studio and it showed all of the div’s lining up nicely, just like they were supposed to be doing, looking like this:

-<div id=”Tab1Content”>
  +<div>
  +<div>
-<div id=”Tab2Content”>
  +<div>
  +<div>

I beat my head against the wall for a while and noticed that in the actual HTML code was generating a lot of empty <div> tags, like:

<body>

  <div id=”Tab1Content”>

    <div id=”row1” />
    <div id=”row2” />

  </div>

  <div id=”Tab2Content”>

    <div id=”row1” />
    <div id=”row2” />

  </div>

</body>

(The above is waaaaaaaaaaaay oversimplified.  The empty div tags are totally valid. Some of my <div> tags were full of content, but many more were not.  I came to the realization that my <xsl:for-each> directives were emitting the short-form div tags when the xsl:for-each didn’t’ find any data.  I forced an HTML comment into the output, as shown:

image

 

After I did that, all the div’s lined up nicely and my tab switching started working.

As always, I hope this helps someone in a pinch.

</end>

Subscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

Yet More jQuery–Resize an Image Example

I inherited a web part from a client’s old vendor and it has an image size problem.  The images should be 60×50 but for some odd reason, the original vendor forced them into 42×42, so they look squashed:

 

Good Image

Bad Image

Here’s the markup (somewhat simplified):

<table class=’extended-outlook’>
  <thead>
    <tr>
      <th  width=’100′>3 Tuesday</th>
    </tr>
  </thead>

  <tbody>
    <tr class=’forecast’>
      <td width=’100′>
        <ul>
          <li class=’high’>High: 72&deg;F</li>
          <li class=’low’>Low: 44&deg;F</li>
          <li class=’condition’>Sunny
            <img src=’
http://deskwx.weatherbug.com/images/Forecast/icons/localized/60×50/en/trans/cond007.png’ width=’42’ height=’42’ alt=” />
          </li>
        </ul>
      </td>
    </tr>

  </tbody>

</table>

You’ll note that even though the path to the image itself shows the proper dimension (60×50) the original vendor forced it in 42×42.  Why?  Crazy.

Anyway, I wanted a quick and easy solution to this issue and I turned to jQuery.  The trick was to locate all of the appropriate <img> tags.  I didn’t want to muck about with any other img tags (of which there are many).  This bit of jQuery did the trick:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>

<script type="text/javascript">
     $(document).ready(function () {

         $(‘li.condition > img’).each(function (index, item)
           
{
             $(item).css("width", "60"); 
             $(item).css("height", "50");
            });
     }); // on document load
</script>

That bit of code finds the collection <li> tags whose class is “condition” and <img> children.  It then iterates through all of that.  Worked like a charm.

I could probably streamline it, but I never was a the kind of unix guy that solved π to 18 digits precision using sed and awk and I’m not that kind if jQuery guy either Smile.

</end>

Subscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

Implement a Global Pop-up Notification System

I wrote up an article for www.sharepoint.briefing.com entitled “Implement a Global Pop-up Notification System.”  This function was implemented for a community college to communicate school closings due to snow and so forth. 

It uses a custom list, out of the box SharePoint web services and some jQuery to do the work.

Here’s a teaser:

image

Read the whole thing here: http://www.sharepointbriefing.com/features/article.php/3918471/Implement-a-Global-Pop-up-Notification-System.htm

</end>

Subscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin

Take Control of your OK and Cancel Buttons

I wrote this article a while back, but looks like I didn’t link to it from my blog at the time, so here goes:

image

This article describes how to force newform.aspx to redirect to one page when the user clicks OK and a different page when she clicks cancel.

</end>

Subscribe to my blog.

Follow me on Twitter at http://www.twitter.com/pagalvin