SPServices Example to Display Links Based on the User’s Location
<UPDATE date=”2011-02-14″>: As of jQuery 1.5, single quotes are *required* around z:row or any other similar node selector. This was actually “required” in previous versions of jQuery, but not enforced.
$(xData.responseXML).find("[nodeName='z:row']")
</UPDATE>
I often get questions like “Why would you use the Web Services? Can’t you just use managed code and be done with it?” Once in a while I do something for a client which makes a nice little example, and here’s one of those.
We want to be able to display a set of links on every page in the SharePoint installation for the user. Those links shouldn’t be visible when the page loads, but only when the user clicks on the My Links link. We’re working in SharePoint 2010 and want to sort of replicate some functionality that we have in the current MOSS environment. That functionality was written with managed code, but that seems like overkill. jQuery and the Web Services is actually a great way to do this because we only need to load the links when the user asks for them, and then we want the user to be able to interact with them client-side.
The links are stored in a central list and each link is tagged with the locations that the link is relevant for. For each user, we want to show the links which correspond to the Location in their user profile.
Here’s an example. Say we wanted to show a link to the cafeteria menu to the folks in LocationA and LocationX, but no one else. In the list, we’d have an item that looked something like this:
- URL:
http://cafeteriaserver/weekmenu.html,Cafeteria Menu
- Locations:
;#LocationA;#LocationX;#
Note the delimiters in the multi-select column for Location. When we call the Web Service to get the items, that’s what we get back, so we have to parse out the actual values to see if the match the current user’s location. Also, the URL in a Hyperlink or Picture column is stored as URL,Label so we need to handle that as well.
Here’s what the jQuery looks like. It’s a little oversimplified so that it makes a better example. We also have some custom CSS in place to format the output nicely, etc. The only thing I wanted to show here was how we could use the UserProfileService and the contents of a custom list to serve up personalized content to the user on demand client-side.
<script type="text/javascript" src="/_layouts/NIBR.Common/scripts/jquery-1.4.2.min.js"></script> <script type="text/javascript" src="/_layouts/NIBR.Common/scripts/jquery.SPServices-0.5.6.min.js"></script> <script type="text/javascript"> $(document).ready(function() { // We only want to fetch the links if the user clicks on the link with the mylinks-link CSS class $(".mylinks-link a").click(function() { // Determine who the current user is var thisUser = $().SPServices.SPGetCurrentUser(); // Get the user's profile so that we can determine their Location var NIBRLocation; $().SPServices({ operation: "GetUserProfileByName", async: false, AccountName: thisUser, completefunc: function (xData, Status) { $(xData.responseXML).find("PropertyData").find("Name[text=Location]").each(function() { Location = ($(this).parent().find("Values").text()); }); } }); // End GetUserProfileByName // For debugging only $("#MyLinks").html("Hello, " + thisUser + "<br/>Your Location is:" + Location + "<br/>Your Links are:<br/>"); // Get the links from the My Links list that correspond to the Location $().SPServices({ operation: "GetListItems", async: false, listName: "My Links", completefunc: function (xData, Status) { var linksHTML = "<ul>"; var matches = 0; // Process the items from the My Links list $(xData.responseXML).find("[nodeName=z:row]").each(function() { var Sites = $(this).attr("ows_Sites").split(";#"); for(var i=0; i < Sites.length; i++) { // If this item is set for display for the user's Location, add a LI to the output if(Sites[i] == Location) { matches++; var url = $(this).attr("ows_URL").substring(0, $(this).attr("ows_URL").indexOf(",")); linksHTML += "<li><a href='" + url + "' >" + $(this).attr("ows_Title") + "</a></li>"; } } }); // If there were matches, output the list if(matches) { linksHTML += "</ul>"; $("#MyLinks").append(linksHTML); } } }); }); // End GetListItems }); </script>
One additional note here. In SharePoint 2010, you should clearly be thinking about using the Managed Matadata Service to contain the values for things like Locations. Because we are upgrading from MOSS to 2010, this hasn’t been a focus. I disagree with this, but the organization I’m working with isn’t ready to flesh out the managed metadata yet.