Posts Tagged ‘SharePoint

17
Nov
09

Collaborating on Building SharePoint Solutions

Bjørn Furuknap, never the shrinking wallflower, posted an article today about SharePoint Configuration vs. Development.

One of the things that always seems to be missing is the bridge between the two approaches.  I’ve lived on both sides of the wall, and as long as there’s a wall, things fail.  SharePoint is a collaboration platform, yet it’s amazing how infrequently I see people collaborating their way toward a solution.

I’m a HUGE proponent of what usually gets called customization and that’s where I choose to play the game.  That doesn’t mean that I can’t or won’t write "code", it just means that in the majority of cases, I don’t think you need to.  (BTW, I don’t know why it is so, but apparently XSL, JavaScript, jQuery, CSS, etc. aren’t "code".  I think that’s horse pucky.  Code is code is code, and you need to do the right things regardless which one you choose.  For gosh sakes, words are code: look at the trouble people get into using *them* incorrectly.)

So the key, to me, is to understand the portfolio of tools you have at your disposal and which is right for the task at hand.  Don’t use a hammer to drive in a screw.  There’s also a *lot* of middle, fuzzy ground where the right answer might be the one that is going to get you to a solution that works OK in a reasonable amount of time.  So maybe you use DVWPs instead of custom Web Parts (or vice versa) from time to time.  As long as you are actually solving a business requirement, everyone wins.

To paraphrase Rodney King, “Why can’t we all just get along?”

11
Nov
09

A jQuery Library for SharePoint Web Services (WSS 3.0 and MOSS): the SPDisplayRelatedInfo Function

Cross posted from EndUserSharePoint.com

SPDisplayRelatedInfo is a function in the jQuery Library for SharePoint Web Services that lets you display information which is related to the selection in a dropdown. This can really bring your forms to life for users: rather than just selecting bland text values, you can show them images and links that are related to their choices.

Example

Let’s take a look at a customized edit form (EditForm.aspx copied into EditFormCustom.aspx) for a SharePoint list. In this list, we’re capturing sales opportunities in my favorite demo list. In addition to everything else, we want to capture the System that the customer might want to buy.

Here’s what the form might look like. It’s pretty humdrum (though it does have SPCascadeDropdowns applied to it so that the Country -> Region -> State relationships are enforced, as well as SPLookupAddNew for easy addition of Regions).

clip_image002

If we use the SPDisplayRelatedInfo function, we can spiff up the form quite a bit. Now when we choose a System, we can display an image of it and a link to the Lead Sales Rep:

When the user makes a different selection, the System Image and Lead Sales Rep will change accordingly. Much nicer, IMHO. What you can display in this manner for each column in your list on the form is really only left to your imagination, based on the available column types. You might include a link to a User Manual, for example, or show a list of available inventory at each of your warehouse locations.

Prerequisites

This is one of the places where you’ll be glad if you’ve followed my previous advice to set up reference lists for things like Products, States, and Regions. In this case, I have a list called Systems, which has three columns:

clip_image006

The System column in my Sales Opportunities list is a Lookup column into the Title column of the System list. That gives us a nice, tight relationship between the System value in the Sales Opportunity and the Title of the Systems list.

Syntax

As with all of the functions in the jQuery Library for SharePoint Web Services, everything is put in place from the UI or SharePoint Designer. There’s nothing to install server-side. You simply need to add references to the core jQuery library and the jQuery Library for SharePoint Web Services and then call the function. See the documentation on the Codeplex site for more details on how to set things up.

SPDisplayRelatedInfo currently takes the following options:

$().SPServices.SPDisplayRelatedInfo({
  columnName: "",// The display name of the column in the form
  relatedWebURL: "", // [Optional] The name of the Web (site) which contains the related list
  relatedList: "", // The name of the list which contains the additional information
  relatedListColumn: "", // The internal name of the related column in the related list
  relatedColumns: [], // An array of internal names of related columns to display
  displayFormat: "table", // [Optional] The format to use in displaying the related information. Possible values are: "table", "list".
  headerCSSClass: "ms-vh2",// [Optional] CSS class for the table headers
  rowCSSClass: "ms-vb", // [Optional] CSS class for the table rows
  debug: true // [Optional] If true, show error messages; if false, run silent
});

In the example above, the function call looks like this:

$().SPServices.SPDisplayRelatedInfo({
  columnName: "System",
  relatedList: "Systems",
  relatedListColumn: "Title",
  relatedColumns: ["System_x0020_Image", "Lead_x0020_Sales_x0020_Rep"],
  displayFormat: "list"
});

So I’m asking SPDisplayRelatedInfo to show me the values in the System_x0020_Image and Lead_x0020_Sales_x0020_Rep columns (these are the StaticNames of the list columns as opposed to the DisplayNames) in the Systems list under the System column in my form using the list display format where the System value matches the Title value. I’m just taking the default CSS classes for the example. As you can see, you can pass in any CSS class you’d like to make the SPDisplayRelatedInfo output match your site branding.

The displayFormat takes one of two options:

  • “table” displays the matching items much like a standard List View Web Part would, in a table with column headers
  • “list” also uses a table, but displays the item(s) in a vertical orientation, like in the example above

How Does It Work?

The SPDisplayRelatedInfo works like this:

  • When the function is first called, it attaches an event handler to the dropdown control. The logic here varies a bit depending on what type of dropdown it is.
  • When the selected option in the dropdown changes, SPDisplayRelatedInfo calls two Lists Web Service operations:
    • GetList on the relatedList to get information about its columns (fields)
    • GetListItems to get the items where the specified column’s value matches the current selection. Note that there can be multiple items returned; generally displayFormat: “table” makes more sense if you’ll want to display multiple items.
  • For each column it’s asked to display, SPDisplayRelatedInfo calls a private function (showColumn) to render the column value based on its type. Most of the normal column types are covered, though locale conversions can’t be done from the client side (yet!).

Conclusion

Quite a few of the early functions I’ve implemented in the library can help you make your forms more interactive and interesting to use. Having worked with data for as long as I have, I know all too well how the GIGO rules can bite you. (Garbage In, Garbage Out, in case you haven’t seen the acronym before.) By utilizing some of the functions like SPDisplayRelatedInfo, you can help your users do a better job adding data into SharePoint lists, and maybe even make it a little bit more fun.

08
Nov
09

SharePoint’s Web Services, jQuery, and the z:row Namespace in Safari and Chrome

jQuery’s totally cross-browser capable, right?  Well, generally, yes.  However, through no fault of jQuery, Safari and Chrome don’t seem to like the z:row namespace that the SharePoint Lists Web Service GetListItems operation returns.  I found a nice workaround for z:row from Mike Hacker to improve cross-browser compatibility.  I added a check for ItemCount up front so that we don’t try to use the getElementsByTagNameNS function in IE if there have been no rows returned legitimately.

Here’s my function.  I call it with the XMLHttpRequest result wherever I’m using GetListItems to get a usable rowset regardless of the browser.

// Find the rows in an XMLHttpRequest.  This includes a workaround for Safari and Chrome's
// aversion to the z:row namespace.
function getZRows(rXML) {
    var rows;
    var itemCount = $(rXML).find("rs\\:data").attr("ItemCount");
    if (rXML.getElementsByTagName("z:row").length == 0 && itemCount == undefined) {
        rows = rXML.getElementsByTagNameNS('*', 'row');
    } else {
        rows = rXML.getElementsByTagName("z:row");
    }
    return rows;
}

I’ve tested this in IE8, Firefox, Safari, and Chrome on my Windows PC.  It still doesn’t seem to solve the issue on Safari for Mac, but I’m getting there.  This will at least let the functions in v0.5.0 of my jQuery Library for SharePoint Web Services work with all of the main browsers on the Windows side of things.

01
Nov
09

jQuery Library for SharePoint Web Services: Interim Update on What’s Coming Up in v0.5.0

This post was also published at EndUserSharePoint.com

While seemingly everyone else in the SharePoint Universe is oohing and aahing over SharePoint 2010, I continue to plod along with my jQuery Library for SharePoint Web Services.  (Follow the library on Twitter: @jQSPWS.) I’m sticking with my belief that we’re all going to be using SharePoint 2007 (WSS 3.0 or MOSS) for a good long time, and my library will help make it work better and more “coolly” for us now rather than waiting for SharePoint 2010.

SharePoint 2010 isn’t totally off my radar screen, however.  I’ve had some discussions with a couple of folks on the SharePoint team at Microsoft about making the library forward compatible with SharePoint 2010.  The SharePoint 2010 Web Services documentation is now available in the SDK at MSDN, with the existing Web Services still available (some with new operations) and new Web Services exposing the new functionality in SP2010, of course.  As I learn more about SharePoint 2010, I’ll be coming up with a strategy for supporting it.

I haven’t had this much fun writing code for a long time.  I get to learn some new approaches to things, code ‘em up, and then help a bunch of you to get them implemented.  I’m having a ball.  For those of you I’ve been interacting with on the Codeplex site in the Discussions and Issue Tracker, I want you to know that I appreciate your patience in working with me to use the library.  It’s still really in its infancy, and because of your willingness to use it now, I’ll be able to come up with a better set of solutions for you and others later.

There are quite a few things coming up in v0.5.0 that are inspired directly from your troubles in early usage, and hopefully that will make it easier going forward.  There are also a bunch of enhancements and new functions on the drawing board.  I’ll let the actual Release Notes cover all of the nitty-gritty details (keep watching them, as they will evolve as the codebase evolves), but here are a few highlights you can expect in v0.5.0, coming in the next few weeks.

  • Better error handling in the key functions - Quite a few of you using the library have never touched scripting before, and that’s fine; I don’t expect you to need to debug the code.  The current implementation of functions like SPCascadeDropdowns and SPDisplayRelatedInfo gives you nothing to go on if they don’t work when you first try to use them.  I’m implementing an optional debug mode for these functions, which I’ll roll out to other functions over time.  It’ll let you know if you’re doing something obviously wrong at first, like calling the function with an invalid option.
  • New functionality – Many of you have asked that I make SPCascadeDropdowns work for multi-select lookup columns, and I’m putting that functionality into this release.
  • Added functions – I’ve been talked about SPAuditScripts for quite a while, but I haven’t gotten it done.  With this library comes a responsibility to help with management of its usage.  The SPAuditScripts function will help you do that by telling you where you or others are using script in Content Editor Web Parts (CEWPs).  I’ll have at least an initial version of this function in the release.
  • Tighter code and efficiency in the existing functions – As with most code, the first iteration isn’t always the best one.  By learning from current usage, I’m aiming to get some better code in place on some of the key functions.
  • Bug fixes – See the list in the Release Notes.

This release will be bigger and take longer than my early iterations; the first releases often had only days between them.  Now that there are so many of you out there actually using the darn thing, I owe it to you to be taking a more thorough and careful approach to new enhancements, especially those which impact existing functionality.  That said, if you’d like to be on the beta testing team, drop me a line through the library’s Codeplex site or my blog.  You’ll get access to the new bits ahead of everyone else and can help make the library better and better for others.  If you do drop me a line, let me know a little about your background and goals; it’ll help me as well.  I’ll probably be reaching out to those of you who have had specific issues to try some new bits out for me to get your feedback as well.

Finally, I’m doing all this because I love it, but several of you have indicated that you’d be willing and interested in contributing to the effort monetarily.  (The offer of French Fries was even better!)  I’m looking into how I can rig something up so that you can contribute to an organization that means a lot to me instead.  Watch for details on that in the upcoming days or weeks.  I do work for a living, of course, so also consider Sympraxis Consulting for your next SharePoint project.  We’ve got a pretty good toolkit.

28
Oct
09

A jQuery Library for SharePoint Web Services (WSS 3.0 and MOSS): Part 2 – How Does It Work?

Cross posted from EndUserSharePoint.com

WebServicesIn my last post, I wrote about why I decided to start building the jQuery Library for SharePoint Web Services. In this post, I’ll tell you a bit about what’s there and how it works. If you’re totally familiar with the SharePoint Web Services, this may all be old hat to you, but I felt it would be useful to explain some of the underlying concepts in what I think of as “English” for those who might get something out of it.

As I’ve mentioned, the fundamental idea for the library was to “wrap” the key SharePoint Web Services which would allow you to talk to SharePoint in real time without full page refreshes. As I looked across the Web Services, I saw clear patterns in how they were called (and some glaring exceptions). The patterns meant that I could do some nice generalizing in my jQuery code. The “core” of the jQuery Library for SharePoint Web Services is the $().SPServices function, which allows you to simply call each Web Service operation.

There is a set of Web Services which are available in WSS 3.0 and MOSS, and then some that are only available in MOSS. The table below shows the Web Services currently available in the library and where they work, along with links to the MSDN documentation:

Web Service WSS 3.0 MOSS MSDN Documentation
Alerts Alerts Web Service
Authentication Authentication Web Service
Forms Forms Web Service
Lists Lists Web Service
Permissions Permissions Web Service
Users and Groups Users and Groups Web Service
Versions Versions Web Service
Views Views Web Service
WebPartPages Web Part Pages Web Service
Webs Webs Web Service
PublishedLinksService   PublishedLinksService Web Service
Search   Search Web Service
UserProfileService   User Profile Web Service
Workflow   Workflow Web Service

I haven’t tried to wrap every single Web Service or every single operation of each. I’ve focused on the Web Services and operations that seemed as if they would provide the most benefit the most often. If I’ve missed something that would be of use to you, then by all means let me know by dropping a comment into the Discussions on the Codeplex site. I’d be happy to add it in the next release.

Each Web Service is called with a Simple Object Access Protocol (SOAP) Envelope which contains information about what you want to accomplish in the SOAP Body. As an example, here’s what the SOAP call for the Lists Web Service’s GetList operation looks like:

<xml version="1.0" encoding="utf-8"?>
  <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:xsd="http://www.w3.org/2001/XMLSchema"  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
  <GetList  xmlns="http://schemas.microsoft.com/sharepoint/soap/">
   <listName>string</listName>
   </GetList>
   </soap:Body>
  </soap:Envelope>

You can see what the SOAP call for any of the SharePoint Web Services needs to look like by going to /_vti_bin/[WebService].asmx. You can tack this onto the end of any URL within SharePoint. Here are a couple of examples:

  • http://servername/_vti_bin/lists.asmx
  • http://servername/sitepath/_vti_bin/workflow.asmx

On those pages, you’ll see what operations are available, and clicking on any of the operation links will show you the SOAP request and response structures. I’ve stared at most of these a lot so that you don’t really have to.

Building the SOAP Request

The SOAP Envelope and SOAP Body “wrappers” are the same for all of the SharePoint Web Services. Think of this wrapper as saying “I’m going to speak SOAP to you.” In my library, I store these wrappers in the SOAPEnvelope.header and SOAPEnvelope.footer variables:

SOAPEnvelope.header = "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body>";
SOAPEnvelope.footer = "</soap:Body></soap:Envelope>";

Next comes what I call the SOAPEnvelope.opheader, or Operation Header. The Operation Header varies based on what operation you want to use. For the most part, the structure of the Operation Header is consistent for all of the operations within a Web Service, but there are a few exceptions. (Naughty developers.) The Operation Header tells the specific Web Service what operation you want to have a chat with.

We also need to have a SOAPAction, which is passed ahead of the request. In the case of the GetList operation above, it looks like this:

http://schemas.microsoft.com/sharepoint/soap/GetList

The SOAPAction is also generally consistent within a Web Service, but not always. (Naughty developers again.)

Finally, we get to what I call the SOAPEnvelope.payload. This is where you pass in the real data that you want to use to talk to the Web Service. In the GetList example above, the payload simply contains the listName, which can be either the text name of the list (e.g., States) or the GUID for the list (e.g., 8BADF8E2-3758-4D1B-9966-045F4A77F73D).

The AJAX Call

Based on what operation you pass into the SPServices function of the library, it builds up the appropriate SOAP call and uses it “talk” to the Web Service using AJAX (shorthand for Asynchronous JavaScript and XML). The AJAX call is amazingly simple:

$.ajax({
   url: ajaxURL, // The relative URL for the  AJAX call
   async: opt.async, // By default, the AJAX calls are  asynchronous. You can specify false to  require a synchronous call.
   beforeSend: function  (xhr) { // Before sending the msg, need  to send the request header with the SOAPAction
     xhr.setRequestHeader("SOAPAction",  SOAPAction);
   },
   type: "POST", // This is a POST
   data: msg, // Here is the SOAP request  we've built above
   dataType:  "xml", // We're  sending XML
   contentType:  "text/xml; charset='utf-8'", //  and this is its content type
   complete:  opt.completefunc // When the call is  complete, do this
});

Calling the Library

To set things up to use the jQuery Library for SharePoint Web Services, you’ll need to add references to it and the core jQuery library in the right context for what you are trying to accomplish. This may mean that you add the references in your master page (if you are going to use jQuery pervasively), in a page layout (if only a certain class of pages will utilize jQuery), or in specific pages (if you want to use some of the functions only on a list’s forms, for example). These references will look something like this:

<script language="javascript" type="text/javascript" src="/jQuery%20Libraries/jquery-1.3.2.min.js"></script>
<script language="javascript" type="text/javascript" src="/jQuery%20Libraries/jquery.SPServices-0.4.1.min.js"></script>

I recommend putting both .js files into a Document Library in the root of your Site Collection called something like “jQuery Libraries”, as above. This way, you can manage them as content. For deployment purposes, you may want to use a generic name for the current version you are using so that you won’t need to update every reference every time you upgrade the .js files:

<script language="javascript" type="text/javascript" src="/jQuery%20Libraries/jquery-latest.min.js"></script>
<script language="javascript" type="text/javascript" src="/jQuery%20Libraries/jquery.SPServices-latest.min.js"></script>

What all this adds up to is that you can use the jQuery Library for SharePoint Web Services to call any of the Web Service operations it wraps as simply as this:

$().SPServices({
   operation:  "GetList",
   listName:  "States",
   completefunc: function  (xData, Status) {
     ...do something...
   }
});

which is a whole lot easier and efficient than trying to decipher all of the SOAP and AJAX requirements for each operation every time.

You can also pass in some optional options:

  • WebURL — If you pass in a Web URL, then that context is used for the ajaxURL in the AJAX call above. If you don’t pass in a WebURL, the current context is used. (The current context is determined by a call to the WebUrlFromPageUrl operation of the Webs Web Service. This is exposed as the public function $().SPServices.SPGetCurrentSite, as it can be a little tricky to determine the current site otherwise.) The WebURL is only useful in the case where the context matters to the result, and this is indicated in the library’s Documentation.
  • async — [true | false], as described above

One important caveat: a lot of people and blog posts will tell you to simply drop jQuery into Content Editor Web Parts (CEWPs). I’m not saying that this is always a bad idea, but it will make keeping track of your jQuery usage pretty difficult. I recommend using SharePoint Designer to put the jQuery into the pages them selves. This allows you to use whatever deployment mechanisms you already have in place for customized (unghosted) pages and also eliminates the possibility that a user will delete or change the jQuery in the CEWPs inadvertently.

I’m working on a function called SPAuditScript which will let you get a report of script usage in CEWPs across a Site Collection. This ought to help with keeping track of things as well as allay some of the fears that IT folks have about non-developers doing developer-like things without any way to track it.

The Results

When you make one of these calls, you get back XML, just as you’ve passed XML into it. As I was building the library, I found that I very often wanted to see what was in that XML in an easy to read format, so I built the $().SPServices.SPDebugXMLHttpResult function. If you’re comfortable with XML and debugging tools, you may never need this function, but I find it useful. If you wanted to use it in the above example, replace the completefunc with this:

completefunc: function (xData, Status) {
   var out =  $().SPServices.SPDebugXMLHttpResult({
     node:  xData.responseXML
   });
   $(divId).html("").append("<b>This  is the output from the GetList operation:</b>" + out);
}

where divId is the ID for a DIV on the calling page where you’d like to place the results. The output from the $().SPServices.SPDebugXMLHttpResult function for GetList will look something like this excerpt:

jQuery Library for SP Web Services

On the other hand, if you’d like to work with the output, you’d probably do something like this:

$().SPServices({
   operation:  "GetList",
   async: false,
   webURL: opt.webURL,
   listName:  opt.listName,
   completefunc:  function(xData, Status) {
     $(xData.responseXML).find("Field").each(function()  {
       if($(this).attr("StaticName")  == opt.columnStaticName) displayName = $(this).attr("DisplayName");
     });
   }
});

This example comes from the $().SPServices.SPGetDisplayFromStatic function. In the completefunc, I find all of the Field elements, iterate through them until I find the one I’m looking for, then grab the DisplayName attribute to return. I’m not going to go into a jQuery tutorial here, but working with the XML SOAP response is often about this simple.

Conclusion

So all of this (hopefully) explains what happens when you use the jQuery Library for SharePoint Web Services function $().SPServices to call a Web Service operation. Any one of these Web Service operations can let you do some spiffy stuff, but to me the real power comes in utilizing one or more operations together to accomplish cool things. For instance, the $().SPServices.SPCascadeDropdowns function uses GetListItem, $().SPServices.SPLookupAddNew uses GetList (2x) and GetFormCollection, and so on.

In my next post, I’ll write about the other functions in the SPServices namespace and how you can use them to improve the user experience in SharePoint.

28
Oct
09

SPCascadingDropdowns Demystified (or Mystified, Depending on Your View)

In my  jQuery Library for SharePoint Web Services, one of the most popular functions is $().SPServices.SPCascadeDropdowns.  The SPCascadeDropdowns function lets you set up cascading dropdowns on SharePoint forms. What this means is that you can enforce hierarchical relationships between column values.  This is sometimes called connected dropdowns or linked dropdowns (or probably other things I haven’t run across yet).

The function uses the GetListItems operation of the Lists Web Service to refresh the allowable values based on relationships which are maintained in reference lists. By implementing this function, you can remove all of the coding requirements to manage the hierarchical relationships (once it is in place) and let your users manage the content.

The requirement that the values be stored in a list seems to baffle many people, as do the basic steps to use the function.  I’m not dissing anyone here.  I know that there are people using this stuff who don’t have a development background.  I see that is a Really Good Thing, and is one of the reasons I’ve implemented the functions in the library the way I have.  But what it can mean is that the underlying concepts may be downright foreign.

Here are some explanations of the most common things I see people struggling with.  I’m going to add these ideas into the documentation, of course, but I thought a blog post might be a good idea, too, as some of these ideas apply in general.

  • The src attribute in <script src="../../jQuery%20Libraries/jquery-1.3.2.js"></script> should point to where *you* put the .js files.  You can store them anywhere that makes sense for your needs.  To reiterate my suggestion in the documentation: I recommend putting them into a Document Library in the root of your Site Collection called something like jQuery Libraries. However, they can be stored anywhere as long as all users who need to access them have read permissions.
  • relationshipListParentColumn and relationshipListChildColumn should be the internal name (also known as the StaticName) for the columns in the relationshipList.  parentColumn and childColumn should be the DisplayNames for the columns on the form.
    • When you first create a column in a list, the name which you give the column becomes the StaticName.
    • The StaticName is encoded, meaning that certain characters are replaced with a set of characters which represent their ASCII value.  So if you name a column Product Description, the StaticName will be Product_x0020_Description. Terms & Conditions becomes Terms_x0020__x0026__x0020_Condit.  _x0020_ = space (" "), _x0026_ = ampersand ("&"), etc.
    • As you can see from the Terms & Conditions example above, the StaticName is limited to 32 characters, including the encoded values.
    • If you aren’t sure what the StaticName for a column is, go into List Settings, click on the column name in the Columns section, and look at the URL.  At the end of the URL, you’ll see a Query String parameter called Field: &Field=Lead%5Fx0020%5FSource.  The string after the = sign is the StaticName, in this case Lead_x0020_Source.  The %5F values are the underscores ("_"_ encoded for the URL.  I know this can be confusing if you aren’t familiar with these concepts.
    • If you subsequently change the column name (like renaming Title to Failure), the StaticName stays static (does not change), but the DisplayName does change.
    • One of the dangers of this is that a column is renamed several times and ends up being used for something entirely different than its original intent.  Because of this, it’s often better to delete a column and add a new one than renaming it.
  • Don’t create the lists to drive the cascading dropdowns *only* to drive the cascading dropdowns.  These lists are the best practice way to manage the choices that are available to a user in list columns.  This is a key concept way beyond the cascading dropdowns idea:
    • Things like States or Regions or Products or Parts ought to be created as Site Columns in the root of your Site Collection which are lookups into lists and then used everywhere in the Site Collection you need them.
    • Because the choices are stored in a list, you can manage them as content as opposed to as settings, applying content management rules or workflows, as needed.
    • Since the values are stored in one place, a change in the list ripples out to every list or library where the Site Column is used.  This is an incredibly powerful capability in SharePoint that is totally underused and ensures information uniformity and a good information architecture.
    • By taking advantage of this capability, you can begin to enforce a common taxonomy of concepts which apply across the organization.  Rather than calling Product 12345 the Blue Widget and the Left Screwed Thing and the One that J&J Buys, we can all call it Product 12345 and understand what we are all talking about.
28
Oct
09

The Customer’s Always Right – Except When They Aren’t

I was asked via an email from this blog to look at a thread in the MSDN SharePoint – Design and Customization forum today.  Of course, I was curious and headed right over there.  Here’s the basic question (there’s lots more detail in the thread):

My problem precisely and concisely is that I get tasked (A Must-Requirement) to offer the client the ability to select a customized CSS class for each single web part individually in order to be applied. The selection MUST be via the Browser: means that the user will pick whatever CSS class suits him/ her from the properties of that particular web part and clicks OK, then Bam! That particular web part will get the new style.

and my answer:

Not having been involved in the discussions with the actual users, I can’t speak to why they feel that this is a useful requirement.  Perhaps coming up with a set of page layouts that represent the normal range of options for them with each Web Part Zone having a specific set of CSS applied to it is the right middle ground.  Rather than trying to solve the “we might want to do anthing” problem, see if you can identify the most common patterns and solve those.  Then you can deal with the exceptions as they arise, which is likely to be infrequent.

I see this sort of thing in the forums a lot.  These “absolute requirements” that the users won’t budge on.  Well, as IT Professionals (or whatever we choose to call ourselves) we owe it to those same clients to sometimes point out that they may be wrong in their estimation of their requirements.  With an infinite amount of time and money, I can make a computer do anything you want, including marrying your daughter and making a perfect Bolognese sauce.  But that’s not realistic, is it?

One of the problems we get into with SharePoint or any other development platform is that we tend to say “Sure” or “No” too much.  There’s a lot of room in the middle: “That might work, but have you thought about…”, “What if we…”,  “I’ll throw in this feature because it’s easy, but let’s talk through your options on this other one…”, etc.  I work with clients who still approach SharePoint with an old-school mentality, and by the time the SharePoint experts are truly involved in the conversation, the requirements are already way out of whack.  We can get them back on track, but it takes more work and it can be painful for those users who think they had already arrived at the answers.

Build a trusting relationship with the user base, help them solve their problems in creative ways, and you’ll be able to have these “you may be wrong about this” discussions more easily.  You owe it to them, and they will succeed more completely due to your efforts.

22
Oct
09

Finding Date/Time Columns on the Page with g_strDateTimeControlIDs

I ran across an interesting little trick in some code I’m working on today.  As usual, not my code, someone else’s that I’m trying to decipher and fix.

One thing that they are doing is sort of slick.  There’s apparently an array created by the datepicker.js JavaScript called g_strDateTimeControlID which is populated with the IDs for all of the date input fields on the page which utilize the Date Picker. (I did some Binging, and there are only 4 references to g_strDateTimeControlID that I found.)  The little calendar icon below is the Date Picker:

DatePicker

You can use the g_strDateTimeControlIDs array like this:

var eventDateID = g_strDateTimeControlIDs["SPEventDate"];
document.getElementById(eventDateID).value = date;

Note the ‘SP’ ahead of the column name.

That’s certainly simpler than writing your own JavaScript/jQuery to find the control, and makes it easy to set the date value, whether it be from a Query String value or some calculation.  Because the array is constructed and used by the Date Picker, so it should be available on the page where ever the Date Picker is seen.

20
Oct
09

Passing a Source Parameter on the Query String with Multiple Other Parameters

I’ve posted on similar tricks to this in the past, but this little trick is really helpful and worth calling out on its own.  Say that you’d like to pass a Source parameter on the query String, as SharePoint often does for you:

http://servername/sites/sitename/Lists/MyList/EditForm.aspx?ID=275&Source=http://servername/sites/sitename/default.aspx

Simple, and you see it all the time as you navigate around in SharePoint. In many cases, you’d also like to pass additional parameters that will “travel along” with the Source parameter.  The trick for this is to simply encode the ampersand (&) character so that it won’t be treated as the start of a new Query String parameter, but instead just a part of the Source parameter. The ASCII value for the ampersand is 26 in hex, so you encode it as %26 in the URL:

http://servername/sites/sitename/Lists/MyList/EditForm.aspx?ID=275&Source=/sites/sitename/default.aspx?ProjectID=123%26Boolean=0%26EmployeeID=345

Note that I’m passing in the relative URL for the default.aspx page.  Get into the habit of using relative URLs all the time and you’ll be in much better shape in general.

With the above URL, when you are finished with the EditForm.aspx page, whether by clicking OK or Cancel, you’ll be redirected to:

http://servername/sites/sitename/default.aspx?ProjectID=123&Boolean=0&EmployeeID=345

19
Oct
09

jQuery Library for SharePoint Web Services v0.4.0 Released

This release contains two functions I’ve wanted to get into the library for a long time: $().SPServices.SPRedirectWithID and $().SPServices.SPRequireUnique.  These two functions show how you can solve tricky problems with jQuery and the SharePoint Web Services much better than any of the other approaches available, IMHO.

$().SPServices.SPRequireUnique allows you to specify a page to redirect to after creating a new list item with a NewForm.aspx (or your customization of it).  The two posts discussing this topic on my blog are together the #1 most read by a long shot. (You can read these two old posts: Redirect to Another Page from NewForm.aspx with the New Item’s ID: Redux and Redirect to Another Page from NewForm.aspx with the New Item’s ID to see where my thinking used to be.)

$().SPServices.SPRequireUnique lets you require unique values in a Single line of text column.  Generally you would use this on the Title column so that you can use a reference list relationally, such as the lists I use in the examples for $().SPServices.SPCascadeDropdowns to contain the States and Regions.

The release is rounded out with a couple of new Lists Web Service operations (CheckInFile and CheckOutFile) and exposing a couple of the nifty “utility” functions ($().SPServices.SPGetLastItemId and $().SPServices.SPSPGetDisplayFromStatic) I wrote in the process of building the first two functions above.

You can download jQuery Library for SharePoint Web Services from Codeplex.

Release Notes

New Functions

Function Description
$().SPServices.SPRedirectWithID This function allows you to redirect to a another page from a new item form with the new item’s ID. This allows chaining of forms from item creation onward.
$().SPServices.SPRequireUnique Checks to see if the value for a column on the form is unique in the list.
$().SPServices.SPGetLastItemId Function to return the ID of the last item created on a list by a specific user. Useful for maintaining parent/child relationships.
$().SPServices.SPSPGetDisplayFromStatic This function returns the DisplayName for a column based on the StaticName.

New Operations

Web Service Operation Options MSDN Documentation
Lists CheckInFile pageUrl, comment, CheckinType Lists.CheckInFile Method
  CheckOutFile pageUrl, checkoutToLocal, lastmodified Lists.CheckOutFile Method

 




 

November 2009
M T W T F S S
« Oct    
 1
2345678
9101112131415
16171819202122
23242526272829
30  

Twitter Updates