SharePoint 2010 : Toggling the Left Navigation Bar with jQuery

Saturday, February 25 2012

This is part 2 of the series: SharePoint 2010, CSS3, HTML5, jQuery & The JavaScript Client Object Model.  In this post, we will be leveraging some of our previous efforts atimage integrating  jQuery into our SharePoint 2010 HTML5 masterpage template and use jQuery “toggle()” to collapse and expand the left navigation panel.  I find it annoying to have two masterpages, one with the left navigation and one without.  In some cases, the left navigation panel can be redundant to the content in the page and interferes with the ability to comfortably fit a three column page layout for the main content.  That left navigation panel just takes too much screen to leave three columns for the main content panel.  Now with a little jQuery magic, you can have it both ways, expanded and collapsed, within a single masterpage.  The best part is, that if you followed along in the first post and uploaded and linked the jQuery libraries to your masterpage template, then you have already done the heavy lifting and the effort to accomplish this task is really quite simple.  We are going to use the “toggle()” function of our jQuery library to accomplish the magic. 

One of the challenges to all SharePoint branding, is understanding the template from which you start  your customized SharePoint masterpage.  I think that is one of the key reasons that we often see the recommendation to start with the “minimal.master” as your starting point.  For better or worse, I personally prefer to start with the full “v4.master” and follow a few very important guidelines to minimize the risk of breaking the site masterpage.  The best advice I’ve seen on this subject is “hide … don’t delete”.  SharePoint makes extensive use of all those content placeholders in the masterpage, and if you delete them, SharePoint is not going to be very nice at all.  Whether you move the unused placeholders to a “<div>” section that is hidden or simply add the “ms-hidden” class to the content placeholder which you chose to hide, you will be safely allowing SharePoint to function as designed even if the content is not displayed.  This is a much more pleasant experience for the end user than the error page.


Let’s start with a quick review of how we integrated the jQuery library into our SharePoint Site.  Remember, in this example, we have placed the library in the content database so that the solution is compatible with SharePoint Online and other SharePoint tenant services. And then referenced them as site collection links within the database.   The end result is the same whether we manually create the folders and upload the files in either the UI or SharePoint Designer 2010, or we build a Web Solution ('”WSP”) package in Visual Studio and deploy it to the server as a site scoped solution.  Remember, if your are deploying the solution as a “WSP” package, that your library and other resources are configured as “modules” within the package.  If you attempt to deploy anything to the file system through mapped folders, or the SharePoint Root folder, you will not be able to deploy the solution as a “sandboxed” solution and it will not be deployable to SharePoint Online.  So, let’s look at the code from the previous post.


In our previous post, we included a reference to our jQuery Libraries.  Because SharePoint uses JavaScript extensively for its own magic, we need to be careful that the scripts that we add to our SharePoint solutions don’t conflict with SharePoint scripts and that our scripts can be loaded once and accessed from anywhere.  As previously mentioned, the masterpage is the perfect place for this. 


Once we have set our DOCTYPE declaration to HTML and content rendering as IE9 compatible, we use the SharePoint:ScriptLink element to allow SharePoint 2010 to link our jQuery Library to the masterpage. The “~site” placeholder in the path for the “name”  attribute tells SharePoint to reference the content from the site collection database.  If we tried to browse to this content with the explorer, we would not be able to find our folders.  SharePoint is using “virtual path providers” to build this site in memory from the content database, and this SharePoint:ScriptLink element provides the capability to retrieve our library from that “virtual path”.  With  these pieces in place we are ready to create some of our own SharePoint magic.


If we want to trigger the expansion and collapse of that Left navigation panel,  we need to first determine how it will be triggered.  The options are limited by creativity and the events available.  I chose to add a tab at the top-right of the NavPanel and trigger the “toggle” action with an “onclick” event on the tab.  This isn’t the “only” choice, it’s simply the one I chose and which works very well for me.   In the previous post I discussed the “unexpected” side effects of some of our decisions, especially when working with masterpages and styles.  I got lucky with my decision when this tab surprised me later in a way which did did not break my solution.  I’ll demonstrate that later.

As mentioned previously, I do most of my edits to masterpages inside SharePoint Developer so that I have as much visual assistance as possible when editing imagethe source.  I tend to use the split pane editor as it gives me the options of traversing the HTML elements by either selecting it in the design view directly or from the navigation bar at the bottom of the design view or I can click the element in the code window, then right-click and select “select Tag”.  In the illustration, I have done this so that I can scroll to just beyond the left Navigation Panel, “s4-leftpanel”,  to add my button. I’ve highlighted the new element in the illustration.  There are a few things to observe. First, the button does NOT have a runat=”server” attribute.  This button runs on the client.  The left navigation panel always exists on the client browser.  We are just toggling its visibility.  I’ve given the element an id, qlAccordian, and two classes, qlExpander and flip, both which will be used later by jQuery. Lastly, I’ve given the button a title value, title="&larr;”, which provides us that nice left arrow when we hover over the button tab. Now we’ve created that little button where we want it.  Next we need to apply our styles and our jQuery magic.


imageIn my CSS file for the masterpage, I have added the qlExpander class and populated the styles that will be used by the button.  You may notice the border-radius on two corners which is part of the CSS3 schema.  I usually use Expressions Web for my editor so that I have the ability to validate my attributes against the CSS3 schema.  In this image, I used the native SharePoint Developer editor and you can see that it did not understand the border-radius attribute.
You may also notice that there is no class added for flip.   In our JavaScript file for the Masterpage, we are using that class attribute in our jQuery selector.  Let’s take a look at that file so that we understand what out JavaScript and jQuery are doing for us.  In the first line, ExecuteOrDelayUntilScriptLoaded($, "sp.js"); we are telling the browser to delay execution until SharePoint has completed loading its script, sp.js.   The $(document).ready(function ()  is used to delay execution until all the elements have been loaded on the client browser.  This avoids the error of trying to access an element that has not yet been loaded. 

 $(".qlexpander.flip").click(function () is the jQuery magic. $  is an alias for jQuery  and we are asking jQuery to build a collection of objects with the flip  class, which in this case is only our new button, and to dynamically attach a click action.  Because I am doing more than just toggling visibility on the panel, $(".panel").toggle();, I needed to set up a global variable to hold the default value (for when the page is first opened), and then toggle it as the button is clicked.  If the button is clicked the first time, the jQuery toggle function changes the left margin on the main content panel, $("#MSO_ContentTable").css("margin-left", '4px');, thus shifting it left over the opening space when the panel is collapsed.  Then I toggle my variable, navIsDisplayed=false;
, and set the title property on the button to a right arrow, $("#qlAccordian").prop("title","→");.  If I click the button a second time, when the navigation panel is hidden, the else section of the code is executed setting everything back to its default values.  For a better understanding of jQuery Toggle(), you can review the documentation here -- .toggle() – jQuery API.   If you notice the commented lines in the JavaScript, those are test stubs that I often use when developing solutions.  Usually, you would delete these before deploying this solution to you production site. 


Remember when I promised to demonstrate one of those SharePoint surprises?  In this case, the dialogs that are used in SharePoint when viimageewing or editing item data also use the same masterpage for their template.  As a result, my little tab makes its appearance on that page too, though luckily, it’s behavior is absent.


So now, if we have done jobs correctly, and all our code is correct and our links to our JavaScript and CSS are correct, we should have our left navigation panel with toggled visibility when we click our button, just like the first image in this post.  Does it work and will it work on a SharePoint Online site?  Absolutely!.  You can see it in action here:  Your logon credentials are User Name: and Password URWelcome@.


That’s enough for this post.  We leveraged jQuery  and created a workable customization that allows us to control the visibility of that left navigation bar and recover more of the screen real estate for our content .   Yet  we maintained the benefits of the quick-launch left navigation panel when the user wants it.   For the next post we move on to Modernizr and Polyfills, and leveraging jQuery with these libraries, to create a consistent user experience across different browsers and versions.  Later, I will be creating Sandboxed solutions for v4.Master and minimal.master and providing links, so that the designers following along can work with these features without as much of the coding.


Thanks for letting me share this with you.  I hope you found it helpful and that you return for the next post.