Workaround – Display Tableau dashboard in SharePoint web part

When the business needs to view Tableau dashboards or visualizations in SharePoint 2010, the most complete solution is to install the Tableau Server Service Application into the SharePoint farm. But what if it is not installed or supported on the farm?

The most obvious workaround is to add a Page Viewer web part to a SharePoint page which points to the URL of the Tableau dashboard page. This method shows the entire Tableau page – navigation header, footer and everything else in-between. But who really wants a page in a page, unless it’s the only option?

To display just the dashboard itself on a SharePoint page, use a Content Editor Web Part. Click the “Share” hyperlink on the Tableau dashboard page, and a dialog is displayed with Email and Embed code strings.


The Embed string in the dialog contains object and param tags:


Just copy and paste them into the HTML Source pane of the Content Editor Web Part.



Finish configuring the web part settings and publish the page to view the Tableau dashboard. Depending on network, server and dashboard conditions, the report may take a few seconds to load at times, but it works.

After publishing the page, it is possible to replace the “Embed” code in the HTML Source Editor code, but SharePoint 2010 makes it a bit tricky. In my case, it took clicking on the content area and hitting the delete key a couple of times to remove a veneer of sorts before the “Edit HTML Source” button would apply to the correct web part on the page. If that fails to satisfy, just create a new Content Editor Web Part to replace the previous one.

Remove HTML formatting from SharePoint Rich Text Editor content with JavaScript

Compared with Microsoft Word, SharePoint’s out of the box Rich Text editor seems like a tool from the dark ages. These days, anyone can use Microsoft Word to format content better than the US Mint could 20 years ago, so when it comes to publishing content in SharePoint, most of us follow the path of least resistance and just paste Word content into the SharePoint editor.

This habit, however, can cause problems when there is a need to re-purpose Rich Text and Enhanced Rich Text content elsewhere in the organization. When Engineering, for example, wants the content without all of Marketing’s 30pt Bodoni Bold fluff, we need a way to dispose of the Word HTML/XML formatting.

Have you ever looked at Word’s HTML? It has a beauty all its own. But good luck at editing it with anything other than the Word client application. Stripping the HTML with a blissfully simple “jQuery(html).text();” JavaScript won’t do in many cases, because it wipes out essential spaces and line returns as well. Regular Expressions will do the job however, but there’s a need for more than one or two.

Fortunately, some good people at 1st Class Media in Edinburgh posted a respectable set of expressions back in 2007 –

function CleanWordHTML( str )
	str = str.replace(/<o:p>\s*<\/o:p>/g, "") ;
	str = str.replace(/<o:p>.*?<\/o:p>/g, "&nbsp;") ;
	str = str.replace( /\s*mso-[^:]+:[^;"]+;?/gi, "" ) ;
	str = str.replace( /\s*MARGIN: 0cm 0cm 0pt\s*;/gi, "" ) ;
	str = str.replace( /\s*MARGIN: 0cm 0cm 0pt\s*"/gi, "\"" ) ;
	str = str.replace( /\s*TEXT-INDENT: 0cm\s*;/gi, "" ) ;
	str = str.replace( /\s*TEXT-INDENT: 0cm\s*"/gi, "\"" ) ;
	str = str.replace( /\s*TEXT-ALIGN: [^\s;]+;?"/gi, "\"" ) ;
	str = str.replace( /\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"" ) ;
	str = str.replace( /\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"" ) ;
	str = str.replace( /\s*tab-stops:[^;"]*;?/gi, "" ) ;
	str = str.replace( /\s*tab-stops:[^"]*/gi, "" ) ;
	str = str.replace( /\s*face="[^"]*"/gi, "" ) ;
	str = str.replace( /\s*face=[^ >]*/gi, "" ) ;
	str = str.replace( /\s*FONT-FAMILY:[^;"]*;?/gi, "" ) ;
	str = str.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3") ;
	str = str.replace( /<(\w[^>]*) style="([^\"]*)"([^>]*)/gi, "<$1$3" ) ;
	str = str.replace( /\s*style="\s*"/gi, '' ) ; 
	str = str.replace( /<SPAN\s*[^>]*>\s*&nbsp;\s*<\/SPAN>/gi, '&nbsp;' ) ; 
	str = str.replace( /<SPAN\s*[^>]*><\/SPAN>/gi, '' ) ; 
	str = str.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3") ; 
	str = str.replace( /<SPAN\s*>(.*?)<\/SPAN>/gi, '$1' ) ; 
	str = str.replace( /<FONT\s*>(.*?)<\/FONT>/gi, '$1' ) ;
	str = str.replace(/<\\?\?xml[^>]*>/gi, "") ; 
	str = str.replace(/<\/?\w+:[^>]*>/gi, "") ; 
	str = str.replace( /<H\d>\s*<\/H\d>/gi, '' ) ;
	str = str.replace( /<H1([^>]*)>/gi, '' ) ;
	str = str.replace( /<H2([^>]*)>/gi, '' ) ;
	str = str.replace( /<H3([^>]*)>/gi, '' ) ;
	str = str.replace( /<H4([^>]*)>/gi, '' ) ;
	str = str.replace( /<H5([^>]*)>/gi, '' ) ;
	str = str.replace( /<H6([^>]*)>/gi, '' ) ;
	str = str.replace( /<\/H\d>/gi, '<br>' ) ; //remove this to take out breaks where Heading tags were 
	str = str.replace( /<(U|I|STRIKE)>&nbsp;<\/\1>/g, '&nbsp;' ) ;
	str = str.replace( /<(B|b)>&nbsp;<\/\b|B>/g, '' ) ;
	str = str.replace( /<([^\s>]+)[^>]*>\s*<\/\1>/g, '' ) ;
	str = str.replace( /<([^\s>]+)[^>]*>\s*<\/\1>/g, '' ) ;
	str = str.replace( /<([^\s>]+)[^>]*>\s*<\/\1>/g, '' ) ;
	//some RegEx code for the picky browsers
	var re = new RegExp("(<P)([^>]*>.*?)(<\/P>)","gi") ;
	str = str.replace( re, "<div$2</div>" ) ;
	var re2 = new RegExp("(<font|<FONT)([^*>]*>.*?)(<\/FONT>|<\/font>)","gi") ; 
	str = str.replace( re2, "<div$2</div>") ;
	str = str.replace( /size|SIZE = ([\d]{1})/g, '' ) ;
	return str ;

Using “Append Text to Query” in Search Core Results

After creating a document library with uniquely named columns, populating the columns with values, and waiting for Search to crawl the library, you set up a Display Group and Scope on the Site Collection Administration Search scopes management page (_layouts/viewscopes.aspx), then add a Search Box and Search Core Results web part to a page and configure them to use your new group and scope. The library documents are displayed, but hmmm… so are the library views and folders.

Naturally, SharePoint Search indexes and returns as much as it can, and it depends on you to filter out what you don’t want. If you can’t filter the results using Scope rules, then one alternative is to use the Search Core Results web part -> Search Core Results Action Links -> Results Query Options -> Append Text to Query field. You could simply add…

isDocument=Yes or IsDocument:1

… to filter out the folders. The difference between the “=” and “:” property operator is spelled out in this MSDN Property Restriction Keyword Queries article.

But, what if your library has a Link to a Document content type that refers to ASPX pages rather than DOC’s or PDF’s? This is where an understanding of the default metadata properties might come in handy. The Search Core Results web part Display Properties -> Fetched Properties lists the default metadata properties used by Search. See this Change how search results appear in the Search Core Results Web Part (Search Server 2010) Technet article for more details.

<root xmlns:xsi="">
		<Column Name="WorkId" />
		<Column Name="Rank" />
		<Column Name="Title" />
		<Column Name="Author" />
		<Column Name="Size" />
		<Column Name="Path" />
		<Column Name="Description" />
		<Column Name="Write" />
		<Column Name="SiteName" />
		<Column Name="CollapsingStatus" />
		<Column Name="HitHighlightedSummary" />
		<Column Name="HitHighlightedProperties" />
		<Column Name="ContentClass" />
		<Column Name="IsDocument"/>
		<Column Name="PictureThumbnailURL"/>
		<Column Name="PopularSocialTags"/>
		<Column Name="PictureWidth"/>
		<Column Name="PictureHeight"/>
		<Column Name="DatePictureTaken"/>
		<Column Name="ServerRedirectedURL"/>

The trick here is to use ContentClass in the Append Text to Query field instead of IsDocument, as in …


Combining multiple items in the Append Text to Query field can be accomplished with a space between each , like …

contentclass:STS_ListItem_DocumentLibrary Size<300000

… which will filter results to list items with a size property of less than 300KB.

To make library column available in the Search Core Results window, map it as a Managed Property in Search and then add it among the other Column Names in the Fetched Properties XML. For example, would fetch values from a crawled library column created with the ungainly name of “PHSPMGDocumentStatus” that let everyone know where it came from and let the System Administrators identify it uniquely among the other crawled Status columns in the system. Once mapped and crawled, you can filter on this column in the search scope or add it to the Append Text to Query field.

What’s more:

  • ModifiedBy:”userlogin”
  • Scopes and the Cross-Web Part Query ID
  • Aggregating Content
  • ContentClass:spspeople
  • Open SharePoint List/Library Link in New Window

    Why can’t a SharePoint list/library web part open links in a new window by default?

    Right… maybe someday.

    There are several workarounds, but here’s one of the “easy” ones that seems to make sense to site owners. It adds some Javascript in an XML Web Part or Form Web Part that’s placed below the list/library web part (maybe, even at the bottom-most zone on the page, no?). Why not use a Content Editor Web Part for the script? Well, it was a fine place to put the script in SP2007, but to survive a migration from SP2007 to SP2010, the XML Web Part seems to be the way to go for small scripts like this, and if already in SP2010, the Form Web Part should do the trick.

    The code looks for the name of the list/library on page load and adds the “target” attribute to the list web part’s table tag. So, say the list name in the current site is called “Links.” The code would look for that list name in the page source by it’s Summary attribute:

    <script language="javascript" type="text/javascript">
    	var tbl = document.getElementsByTagName('table');
    		for(var i = 0; i < tbl.length; i++)
    		if(tbl[i].getAttribute("Summary") == "Links")
    			var anc = tbl[i].getElementsByTagName('a');
    			for(var j = 0; j < anc.length; j++)
    				anc[j].setAttribute('target', '_blank');

    For more than one list/library on the page, the code is a bit different…

    <script language="javascript" type="text/javascript">
    	var tbl = document.getElementsByTagName('table');
    	for(var i = 0; i < tbl.length; i++)
    	if(tbl[i].getAttribute("Summary") == "Links1" 
    	|| tbl[i].getAttribute("Summary") == "Links2"
    	|| tbl[i].getAttribute("Summary") == "Links3"
    		var anc = tbl[i].getElementsByTagName('a');
    		for(var j = 0; j < anc.length; j++)
    			anc[j].setAttribute('target', '_blank');

    Calculated Columns for Cascading Drop-Downs in SharePoint Lists and Libraries

    SharePoint list or library users need a simple way to enter data in one column that depends on what was entered in another, but out-of-the-box SharePoint 2007 or 2010 does not support direct cascading functionality. Using jQuery for SharePoint Web Services might be an option for cascading drop-downs, but you are not allowed to use SharePoint Designer to modify the EditForm, and besides, you want the behavior to work inside the list/library itself in datasheet view and not just in the EditForm. Lookup columns could do the trick, but let’s say you’re already at the farm-wide threshold setting of eight per list/library. Managed Metadata in the Term Store perhaps? But, the terms are not universal and getting a few simple entries requires more than a few clicks.

    If there are only a few fields that relate to one another, one straightforward option might be to create a Choice column that allows users to select a delimited text string that contains all of the relationships in a single line, and then use Calculated Columns to parse the string out into separate columns.

    For example, a Choice column called “Section – Category” could delimit a drop-down menu of sections and categories with a semi-colon character, making it pretty easy for people to spot the combo they’re looking for:

    1 – Pre-Visit; 1 – Charting
    1 – Pre-Visit; 2 – Phone Calls / Messaging
    1 – Pre-Visit; 3 – Registration
    1 – Pre-Visit; 4 – Scheduling
    2 – Patient Visit; 5 – Check-in
    2 – Patient Visit; 6 – Chronic Care / Education
    2 – Patient Visit; 7 – MyChart
    2 – Patient Visit; 8 – Orders / Charting
    2 – Patient Visit; 9 – Rooming
    3 – Post-Visit; 10 – Charting
    3 – Post-Visit; 11 – Orders
    3 – Post-Visit; 12 – Phone Calls / Messaging
    4 – Bars; 13 – Between Visits
    4 – Bars; 14 – Daily Work & General

    One calculated column called “Section” and another called “Category” could contain formulas that split the string into left and right contents. But let’s take it up a notch and turn the string into four columns – “SectionID”, SectionTitle”, CategoryID”, and “CategoryTitle.” See where this is going?

    SectionID – the formula is pretty basic, but it’s not just getting the first character from the left in the string, because the number might end up with more than one character. It’s about getting everything to the left of the first space ” ” character. Now, note this dash has spaces around it. This is important visually for users, but it also serves to make it different than any hyphens used in the words. So, after finding the ” – ” character, the space needs to be subtracted with a “-1” thusly:

    =LEFT([Section - Category],FIND(" ",[Section - Category])-1)

    SectionTitle – here the formula starts getting a bit more complex. We want the words to the left of the “;” and to the right of the ” – “. Note the use of “-1” here too to remove spaces around the dash, and also note that there is a space on the right of the dash in “- “:

    =RIGHT(LEFT([Section - Category],FIND(";",[Section - Category])-1),LEN(LEFT([Section - Category],FIND(";",[Section - Category])-1))-FIND("- ",LEFT([Section - Category],FIND(";",[Section - Category])-1))-1)

    CategoryID – same fun, but now wanting all the numbers from the string on the right of the “;” that are left of the ” – ” on the right hand string:

    =LEFT(RIGHT([Section - Category],LEN([Section - Category])-FIND(";",[Section - Category])-1),FIND(" -",RIGHT([Section - Category],LEN([Section - Category])-FIND(";",[Section - Category])-1))-1)

    CategoryTitle – not as simple as it looks, this task is to get all the words from the right side of the “;” and the right side of the ” – ” that’s in the right side string;

    =RIGHT(RIGHT([Section - Category],LEN([Section - Category])-FIND(";",[Section - Category])),LEN(RIGHT([Section - Category],LEN([Section - Category])-FIND(";",[Section - Category])))-FIND("- ",RIGHT([Section - Category],LEN([Section - Category])-FIND(";",[Section - Category])))-1)

    Selecting a single item in the Choice column like “1 – Pre-Visit; 1 – Charting” yields:

    SectionId SectionTitle CategoryId CategoryTitle
    1 Pre-Visit 1 Charting

    This method of creating cascading drop-down columns can work well as long as the choices are simple – meaning limited to two to three columns. The formulas can get as complex as your brain can comprehend, and calculation speed does not seem to be an issue.

    Generate a hierarchical XML file from SharePoint list

    You need to get data from a SharePoint 2010 list and generate a hierarchical XML file that can be used as a data source for a Flash movie on a site. Your enterprise SharePoint Admins want their platform to stay as out of the box as possible, and they have good reasons to minimize server-side customizations and the use of SharePoint Designer.

    Undaunted, you turn to the SharePoint Client Object Model for a console application that can be launched from a button on a page or by a workflow. In effect your app needs to perform the following automation tasks:

    • Get a flat XML file of the data
    • Convert the flat XML file into a hierarchical file
    • Save the file as an XML document and upload it to a SharePoint document library

    Step 1 – Get data to a flat XML file
    The first step is to get data from a SharePoint list and store it as XML in memory. This could be done in one of several ways: SPList class and a CAML SPList class and LINQ query, Web Services, GetListItems, or the URL protocol of the RPC method. This solution will use URL Protocol, because it’s a simple and transparent way to access the data. This step also needs to:

    • Get the XML output from a special View of the list rather than the default view of the list, so all of the columns can be shown all of the time without affecting data entry or management
    • Trim off any extraneous characters from the values that come from SharePoint lists, like dates, URLs, or strings delimited with “;#”
    • Resolve a potential SP2010 security exception when accessing from the localhost
    • Build a valid URL to the document, regardless of whether it is a PDF or a Web link
    using System;
    using System.Linq;
    using System.Xml;
    using System.Xml.Linq;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    // used for uploading - clientcontext and memorystream
    using Microsoft.SharePoint.Client;
    using System.IO;
    namespace PMGDialXML
        class Program
            static void Main(string[] args)
                // Use the URL protocol of the RPC method to get data from
                // the "XML Generator View" which displays all of the fields
                string sUrl = "http://rootweb/site/subsite/_vti_bin/owssvr.dll?Cmd=Display&List={E3DFD89F-4DA3-4418-8674-D692B59CCBC4}&View={4E44F267-C5F7-42B6-8871-0194604177EA}&XMLDATA=TRUE";
                // Resolve a potential SP2010 security exception when accessing from the localhost
    	         XmlUrlResolver xmlResolver = new XmlUrlResolver();
    	         xmlResolver.Credentials = System.Net.CredentialCache.DefaultCredentials;
    	         XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
    	         xmlReaderSettings.XmlResolver = xmlResolver;
                // Define LINQ Namespace objects (System.XML.Linq)
                XNamespace s = "uuid:BDC6E3FA-6DA3-11d1-A2A3-00AA00C14882";
                XNamespace dt = "uuid:C2F41030-65B3-11d1-A29F-00AA00C14882";
                XNamespace rs = "urn:schemas-microsoft-com:rowset";
                XNamespace z = "#RowsetSchema";
                // Get the list XML (System.XML)
                XDocument sUrlDoc = XDocument.Load(XmlReader.Create(sUrl, xmlReaderSettings));
                // Store fields returned from owssrv in a new XML variable
                var xVar =
                    new XElement("vWorkflows",
                        sUrlDoc.Root.Descendants(z + "row").Select(r => new XElement("vSection",
                            new XAttribute("sectionTitle", TrimValue(r.Attribute("ows_SectionTitle").Value)),
                            new XAttribute("sectionId", TrimValue(r.Attribute("ows_SectionID").Value)),
                            new XAttribute("show", (r.Attribute("ows_ShowOrHide").Value)),
                            new XElement("vCategory",
                                new XAttribute("catTitle", TrimValue(r.Attribute("ows_CategoryTitle").Value)),
                                new XAttribute("catRef", TrimValue(r.Attribute("ows_CategoryID").Value)),
                                new XElement("vType",
                                    new XAttribute("typeTitle", TrimValue(r.Attribute("ows_TypeTitle").Value)),
                                    new XAttribute("typeRef", TrimValue(r.Attribute("ows_TypeID").Value)),
                                    new XElement("vLink",
                                        new XAttribute("linkNum", ""),
                                        new XElement("linkTitle", TrimValue(r.Attribute("ows_Document").Value)),
                                        new XElement("linkUrl", WhatsUpDoc(TrimValue(r.Attribute("ows_Document_x003a_FileName").Value) + ";" + TrimValue(r.Attribute("ows_Dial_x0020_Title_x003a_DocumentU").Value))),
                                        new XElement("linkSummary", ""),
                                        new XElement("linkKeywords", ""),
                                        new XElement("pubDate", TrimDate(TrimValue(r.Attribute("ows_Document_x003a_PublishDate").Value))),
                                        new XElement("lastUpdate", TrimDate(TrimValue(r.Attribute("ows_Document_x003a_LastUpdated").Value)))

    Step 2 – Construct hierarchical XML document
    Read (aka query) the in-memory XML and reconstruct the a collection of elements and attributes into a hierarchical XML output using LINQ to XML. Note that the results of one LINQ query expression can be the input of another LINQ expression. Code it in a way that matched up with the XML output to make it easier for those that follow. And a few other things:

    • If item is set to “Show” in the list then show it, otherwise hide it.
    • Sort the output by SectionId rather than by SectionTitle to conform to the SWF design and match the existing XML exactly
               // Create new hierarchical XML document from the flat XML variable
                XDocument xDoc = new XDocument(
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XComment("XML Source Data for Dial Flash"),
                    new XElement("workflows",
                        from sec in xVar.Elements("vSection")
                        where (string)sec.Attribute("show").Value == "Show"
                        orderby (string)sec.Attribute("sectionId").Value ascending
                        group sec by new {
                            secT = (string)sec.Attribute("sectionTitle").Value,
                            secId = (string)sec.Attribute("sectionId").Value
                        } into gsec
                        select new XElement("section",
                            new XAttribute("sectionTitle", gsec.Key.secT),
                            new XAttribute("sectionId", gsec.Key.secId),
                            from cat in gsec.Elements("vCategory")
                            orderby (string)cat.Attribute("catTitle").Value ascending
                            group cat by new {
                                catT = (string)cat.Attribute("catTitle").Value,
                                catId = (string)cat.Attribute("catRef").Value
                            } into gcat
                            select new XElement("category",
                                new XAttribute("catTitle", gcat.Key.catT),
                                new XAttribute("catRef", gcat.Key.catId),
                                from typ in gcat.Elements("vType")
                                orderby (string)typ.Attribute("typeTitle").Value ascending
                                group typ by new {
                                    typT = (string)typ.Attribute("typeTitle").Value,
                                    typId = (string)typ.Attribute("typeRef").Value,
                                } into gtyp
                                select new XElement("type",
                                    new XAttribute("typeTitle", gtyp.Key.typT),
                                    new XAttribute("typeRef", gtyp.Key.typId),
                                    from lnk in gtyp.Elements("vLink")
                                    orderby (string)lnk.Attribute("linkNum").Value ascending
                                    group lnk by new {
                                        linN = (string)lnk.Attribute("linkNum").Value,
                                        linT = (string)lnk.Element("linkTitle").Value,
                                        linU = (string)lnk.Element("linkUrl").Value,
                                        linS = (string)lnk.Element("linkSummary").Value,
                                        linK = (string)lnk.Element("linkKeywords").Value,
                                        pubD = (string)lnk.Element("pubDate").Value,
                                        lasU = (string)lnk.Element("lastUpdate").Value
                                    } into glnk
                                    select new XElement("link",
                                        new XAttribute("linkNum", glnk.Key.linN),
                                        new XElement("linkTitle", glnk.Key.linT),
                                        new XElement("linkUrl", glnk.Key.linU),
                                        new XElement("linkSummary", glnk.Key.linS),
                                        new XElement("linkKeywords", glnk.Key.linK),
                                        new XElement("pubDate", glnk.Key.pubD),
                                        new XElement("lastUpdate", glnk.Key.lasU)

    Yep, there’s another way to do it that groups the top level, but we won’t do that here. It looks something like this …

    	   // Alternate way to do it
    	   var query = xVar.Elements("vSection").
    	      OrderBy(grp => (string)grp.Attribute("sectionTitle").Value).
    	      GroupBy(grp => (string)grp.Attribute("sectionTitle")).
    	      Select(grp => new XElement("section", grp.First().Attributes(),
    	            grp.Select(vsec => new XElement("category",
    	   var xml = new XElement("workflows", query);

    Step 3. Save XML document to document library
    This is where the Client Object Model comes in. You’ll also use System.IO for memorystream.

                // Save XML Document to a string
                string upDoc = xDoc.ToString();
                // Upload XML Document to a SharePoint Document Library
                public static void UploadXmlFile(string xmlContent)
                // Define the site, library and file variables
                string webUrl = "",
                       siteUrl = "/site/subsite/subsubsite",
                       libraryName = "documents",
                       fileName = "swf_file.xml";
                // Instantiate the site
                ClientContext clientContext = new ClientContext(webUrl + siteUrl);
                // Process the XML file
                using (MemoryStream memoryStream = new MemoryStream())
                    // Write the file XML contents into a MemoryStream object ...
                    StreamWriter writer = new StreamWriter(memoryStream);
                    memoryStream.Position = 0;
                    // ... and save it in the Document Library (set to "true" to overwrite the file)
                    Microsoft.SharePoint.Client.File.SaveBinaryDirect(clientContext, siteUrl + "/" + libraryName + "/" + fileName, memoryStream, true);

    This code feeds a Flash movie that allows users to dial in on documents by a predefined taxonomy on a SharePoint site. What once required hours of manual XML file edits and uploads can now be done in one click, and the door is now open to automating the entire document upload, approval and management process using workflows and InfoPath web forms. Presumably, this kind of approach can also be used with other kinds of animated web parts that use XML as a data source.

    Reporting Services web parts on SharePoint page

    Adding Report Builder web parts to SharePoint 2010 made the page colorful and intelligent, but the UI lacked a bit. The parts that took up little horizontal space and lots of vertical space looked kind of goofy;

    • the data abruptly cut off vertically after 11 inches
    • they required a fixed vertical setting at about 2000px
    • they would not flow horizontally with the page’s liquid layout
    • they sometimes created two layers of scroll bars making moving around on the page very awkward

    Data typically cuts off vertically after a certain length because of paging; the page breaks based on the Interactive Size setting of the Report pane set in Report Builder. The fix is to set the InteractiveSize settings to 0. Might as well do it on both horizontal and vertical properties.

    Avoid the fixed vertical and horizontal web part settings in SharePoint by using a wee bit of jQuery, unless you are free to do it with a server-side package. Start by removing any Height and Width settings in the web part.

    Then add jQuery code in an HTM file strategically placed in a Documents Library like “Scripts” at some root site and call the file from a Content Editor web part on the report page. The following code seems to work – it works on ALL Report Builder web parts on the page and avoids conflicts with other parts.

    <style type="text/css">
    	.dynamic-height {height:auto !important;}
    <script src="http://domainname/somerootsite/scripts/jquery-1.6.2.min.js"></script>
    <script type="text/javascript">
    	// use setTimeout method to delay
    	$(window).load(function() {
    <script type="text/javascript">
    	function FixReport() { 
    		// fix report height
    		$('div[RSViewer="RSViewer"] div').addClass('dynamic-height');
    		// remove report horizontal scrollbar
    		$('div[id$="ReportViewer"]').css("overflow-x", "hidden");

    Even if the Report Builder web parts only have 2″ to 5″ of width, you can extend the part up to 12″ wide. It will allow a single column page fill out nicely to the right when the browser expands to fit larger screens – same for parts in side-by-side zones.

    See Article 1, Article 2, and Article 3