Skip to main content

Ram's Blog

Go Search
Home
Blog
Events
About
  

RGOPINATHAN.COM > Ram's Blog
SharePointBlogs.Add(this)
Building a customized document library filtering using content editor webpart and javascript

This is a very long overdue post, I have implemented this back in SPS 2003 and same approach works in current version of SharePoint either WSS or MOSS. In this post I will cover how you can implement a custom document library filtering functionality into your site using content editor webpart, javascript, and xml with out writing any assembly code. 

For demonstration purpose I’ll use the default “documents” document library and added 2 custom columns department and language respectively. Department column is a lookup column based on custom list called “Departments”. Departments custom list contains all departments. The second column language is a choice column with English, Spanish, and French values

I also created a new custom page and added the content editor webpart and the list view webpart for “documents” document library. There are two re-usable javascript libraries used in this solution, I will provide a link to download them at the end of the post, after you download the script files, you can create a document library within your site to store those scripts as we will be referencing those scripts.

Implementing the filter criteria Interface using content editor webpart

HTML snippet below is added to content editor webpart, contains 2 select controls one for departments and the other for author (depending on your requirements this might vary for your scenario). I also have a language field which will display dropdown, radio button or checkbox depending on how the choice column is configured on server, finally there is a button control, when user clicks on it, will implement document library filtering using the criteria specified.

<table id="filterCriteriaTable">
    <tr>
        <td>Department:</td>
        <td><select id="departmentsDropDownList" /></td>
        <td>Author :</td>
        <td><select id="authorDropDownList" /></td>
    </tr>
    <tr>
        <td>Language:</td>
        <td colspan="3"></td>
    </tr>
    <tr>
        <td colspan="4"><input type=Button Value="Filter" onclick="Filter();"/></td>
    </tr>
</table>
Preview of Filter Page

filterDocLibPost

Javascript References

There are two javascript references that need to be added right above the HTML snippet shown above in the content editor webpart. I’m referencing script files from “_layouts” directory, like I mentioned earlier you can always create a document library in your site, upload these files and reference the script files from document library directly instead of “_layouts”

   1: <script type="text/javascript" language="javascript" src="/_layouts/EWE/SharePointListHelper.js" />
   2: <script type="text/javascript" language="javascript" src="/_layouts/EWE/DropDownLoader.js" />

SharePointListHelper.js is a javascript library that provides sharepoint lists webservice integration, makes low level SOAP calls using the “XmlHttp” object. SharePointListHelper supports both synchronous and asynchronous calls to sharepoint list webservice methods. DropDownLoader script library has one public method “LoadDropDown” which is used to databind an HTML select control to a sharepoint list and uses methods in SharePointListHelper library for list integration.

Binding HTML Select in content editor webpart to a sharepoint list

The filter criteria interface implemented with content editor webpart contains 2 dropdown list controls, department and author, If you take a close look at the HTML snippet you’ll notice there are no option elements defined inside the select tag, this is because we want to dynamically bind it to sharepoint list (‘departments’, ‘userinfo’ respectively).

Add the Javascript code snippet from below to the content editor webpart. As you can see in the “LoadDropDowns” helper function I’m constructing a DropDownLoader object which is defined in the “DropDownLoader.js” by passing url as parameter, immediately followed by a call to “LoadDropDown” method. Since we have 2 dropdown controls Department and Author we are calling “LoadDropDown” method twice one for each select control. Again your scenario this might be different. Since we want the “LoadDropDown” method to run when the page is loaded a call to “_spBodyOnLoadFunctionNames.push” accomplishes that.

   1: function LoadDropDowns()
   2: {
   3:     var ddl = new DropDownLoader("http://ramgmossdev");
   4:     ddl.LoadDropDown("Departments", "departmentsDropDownList", "ows_Title", "ows_Title", "");
   5:     ddl.LoadDropDown("UserInfo", "authorDropDownList", "ows_Name", "ows_Name", "");
   6: }
   7: _spBodyOnLoadFunctionNames.push("LoadDropDowns");

Figure below show HTML select control in content editor webpart bound to a sharepoint list.

filterDocLibPost4

Displaying the Language choice column in Filter Criteria View

Goal here is to display the language column based on how its configured in sharepoint, for ex ‘DropDown’, ‘Radio Buttons’, or ‘CheckBoxes’. In the javascript code snippet inserted below from the content editor, I’m getting the document library fields by calling “GetListFields” method on SharePointListHelper which calls ‘GetList’ method on Lists webservice. Once we get the list information from server I look for a Field element with name ‘Language’. If language field is found, code would then dynamically create the element and appends it to the table column.

   1: var languageFieldInfo ;
   2: function AppendInputTag(inputType, inputValue, inputName, tableCell)
   3: {
   4:     var inputElm;
   5:     var spanElm ;
   6:     try
   7:     {
   8:         spanElm = document.createElement("span");
   9:         spanElm.innerText = inputValue ;
  10:         inputElm = document.createElement('<input name="' + inputName + '" type="' + inputType + '" value="' + inputValue + '">' + inputValue + '</input>');
  11:     }
  12:     catch(err)
  13:     {
  14:         inputElm = document.createElement("input");
  15:         inputElm.setAttribute("type", inputType);
  16:         inputElm.setAttribute("value", inputValue);
  17:         inputElm.setAttribute("name", inputName);
  18:     }
  19:     tableCell.appendChild(spanElm);
  20:     tableCell.appendChild(inputElm);
  21: }
  22: function BuildFilterCriteriaView()
  23: {
  24:     var spList = new SPList("http://ramgmossdev");
  25:     languageFieldInfo = spList.GetListFields("Documents").selectSingleNode("Field[@Name = 'Language']");
  26:     if(languageFieldInfo != null)
  27:     {
  28:         var table = document.getElementById("searchTable");
  29:         var fieldType = languageFieldInfo.attributes.getNamedItem("Type");
  30:         var format = languageFieldInfo.attributes.getNamedItem("Format");
  31:         var defaultNode = languageFieldInfo.selectSingleNode("Default");
  32:         var choiceNodes = languageFieldInfo.selectNodes("CHOICES/CHOICE");
  33:         if(fieldType.nodeValue == 'MultiChoice')
  34:         {
  35:            for(var i=0; i<choiceNodes.length; i++)
  36:            {
  37:                 AppendInputTag('checkbox', choiceNodes[i].text, 'language', table.rows[1].cells[1])
  38:            }
  39:         }
  40:         else
  41:         {
  42:             switch(format.nodeValue)
  43:             {
  44:                 case "Dropdown":
  45:                     var select = document.createElement("select");
  46:                     for(var i=0; i<choiceNodes.length; i++)
  47:                     {
  48:                       var optionElement = document.createElement("OPTION");
  49:                       select.options.add(optionElement);
  50:                       optionElement.innerText = choiceNodes[i].text ;
  51:                       optionElement.value = choiceNodes[i].text;
  52:                       if(choiceNodes[i].text == defaultNode.text)
  53:                       {
  54:                          optionElement.selected = true ;  
  55:                       }
  56:                     }
  57:                     table.rows[1].cells[1].appendChild(select);
  58:                     break;
  59:                 case "RadioButtons":
  60:                     for(var i=0; i<choiceNodes.length ; i++)
  61:                     {
  62:                         AppendInputTag('radio', choiceNodes[i].text, 'language', table.rows[1].cells[1])
  63:                     } 
  64:                     break;
  65:             }
  66:        } 
  67:     }
  68: }
  69: _spBodyOnLoadFunctionNames.push("BuildFilterCriteriaView");
Filter It

Since SharePoint document library filtering is all querystring based, we are going to leverage this from a javascript method in content editor webpart. The trick is building the querystring exactly like sharepoint does when you filter a document library.

There is two of things we need find before implementing the filter

  1. view GUID for the “documents” list view.
  2. Internal field names for all columns used in filter criteria view

To find out the view GUID and internal field names you can click on the column header dropdown and select one of the values.

filterDocLibPost2

Copy the GUID and Internal Field Name from the header, also notice the querystring format, we are going to build the querystring similar to it from our filter method so we can leverage out of the box document library filtering

filterDocLibPost3

Filter method in Javascript code snippet below builds querystring based on the filter criteria specified and re-loads the page.

   1: function Filter()
   2: {
   3:     var qs = "?View=%7b7B73B297-4DFA-4E1D-864D-9F00337F4FE6%7d" ;
   4:     var filterField = "FilterField" ;
   5:     var filterValue = "FilterValue" ;
   6:     var i=0;
   7:     var deptDropdown = document.getElementById("departmentsDropDownList");
   8:     var authorDropDown = document.getElementById("authorDropDownList");
   9:     var language = document.getElementsByName("language");
  10:  
  11:     if(deptDropdown != null & deptDropdown.selectedIndex != -1)
  12:     {
  13:         i++;
  14:         qs += "&" + filterField + i + "=Department&" + filterValue + i + "=" + deptDropdown.options[deptDropdown.selectedIndex].value ;
  15:     }
  16:     if(authorDropDown != null & authorDropDown.selectedIndex != -1)
  17:     {
  18:         i++ ;
  19:         qs += "&" + filterField + i + "=Author&" + filterValue + i + "=" + authorDropDown.options[authorDropDown.selectedIndex].value ;
  20:     }
  21:     if(language != null)
  22:     {
  23:         var format = languageFieldInfo.attributes.getNamedItem("Format");
  24:         if(format != null & format.nodeValue == "Dropdown")
  25:         {
  26:             i++;
  27:             qs += "&" + filterField + i + "=Language&" + filterValue + i + "=" + language.options[language.selectedIndex].value ;
  28:         }
  29:         else
  30:         {
  31:             for(var j=0; j<language.length; j++)
  32:             {
  33:                 if(language[j].checked)
  34:                 {
  35:                    i++;
  36:                    qs += "&" + filterField + i + "=Language&" + filterValue + i + "=" + language[j].value ;
  37:                 }
  38:             }
  39:          }
  40:     }
  41:     location.href = GetUrlWithOutQs() + qs ;  
  42: }
  43: function GetUrlWithOutQs()
  44: {
  45:     var url = location.href ;
  46:     var tokens = url.split("?");
  47:     return tokens[0] ;
  48: }
Conclusion

This approach is only a workaround, if out of the box document filtering doesn’t satisfy your requirements and you have constraints on writing assembly code this approach might come handy. You should evaluate all options, custom filter webpart, etc before deciding the correct approach.

Links to Download

To download DropDownLoader.js click here

To download SharePointListHelper.js click here

Testing blog post from livewriter

You guys wont believe how I got this work, I was not able to configure the blog account to my hosted one first time when I opened live writer, I then connected to a blog site on my Hyper-V, livewriter played nice and opened up, after that I went and updated account settings point it to my hosted blog and it worked.

Hey I'm happy it works now yippee!!!

Now lets see if publish works

<update>Ok it published but the publish date and time was wrong. What the heck is going on, you guys seen this?

I'm using live writer version that works with windows server 2008, hey atleast I'm able to author blog offline and publish, I can live with updating publish date manually, if any of you have any suggestions let me know</update>

<udpate>ok I do see a set publish date option in live writer, getting used to livewriter now</update>

Importing business data catalog application definition file using a feature
BDC is one of the major enhancements in SharePoint 2007, if you are new to BDC there are many blogs and articles that cover BDC so I'm not going to try to get into what BDC is in this post. I suggest looking at SharePoint Magazine article on "Everything you need to know about BDC"
 
I do want to touch on how you can import BDC application definition file using a Feature. I wrote a Feature Receiver class that plugs into Feature Activated event and Imports the Application Definition file into BDC using object model. It also plugs into Feature Deactivated event and deletes the application from BDC.
 
If you are leveraging BDC in your project and you have multiple sharepoint environments (DEV/TEST/PROD for ex)
challenge you will run into is how do you keep track of specific settings for each environment. For instance if your application definition file contains database connection information or entity actions that refers to a URL, you may be using Web Service endpoints, these settings are going to be different in different environments.
 
One of the things the feature receiver does is it determines what the default ssp for the farm and reads a SSP settings configuration file which stores all the settings that need to be merged and merges those settings to application definition file before importing the application definition file into BDC.
 
You can download the feature receiver project and source files here
 
Here is how you can implement this in your project:

Download the project and source files, drop the "InstallBDCAppDefFile.Actions.dll" assembly in global assembly cache

Create a feature folder within your project and add your business data catalog application definition file, Feature.xml file and a configuration file to store Ssp Settings (you can name the config file what ever you want)

Here is a Feature.xml file from my project, Feature is wired up to the receiver assembly and class, also has 2 properties "ApplicationDefintionFile" and "SspSettingsFile", value for these properties should be the name of your application definition file and ssp settings configuration file without the file extension. Feature receiver will add the .xml and .config extension before reading the file.

<Feature
  Id="{50CFA72F-7963-4f6a-A28C-39B6E8582DE6}"
  Title="Import BDC Application Definition Feature"
  Description="Feature to Import BDC Application Definition File into Business Data Catalog"
  Hidden="FALSE"
  Scope="Site"
  ImageUrl=""
  ReceiverAssembly="InstallBDCAppDefFile.Actions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9abebdc78413d24b"
  ReceiverClass="InstallBDCAppDefFile.Actions.FeatureEventReceiver" 
  xmlns="http://schemas.microsoft.com/sharepoint/">
  <Properties>
    <Property Key="ApplicationDefinitionFile" Value="BDC_ResourceAutomotiveConsultingInstance" />
    <Property Key="SspSettingsFile" Value="SSPSettings"/>
  </Properties>
</Feature>

Below is contents of Ssp settings configuration file from my project. In this scenario BDC pulls data from backend SQL server database so I'm storing Database connection settings for SSP on my local machine, for each environment you have you would have multiple SSP elements in your SSP settings configuration file to store settings for that SSP. Couple of other things I want to point out here is Namespace prefix element is used inside the feature receiver to setup namespacemanager for selecting node using "SelectSingleNode" method.

<SspSettings>
  <NamespacePrefix>ra</NamespacePrefix>
  <Ssp Name="DefaultSSP" Description="Local">
    <MergeSetting NodePath="/ra:LobSystem/ra:LobSystemInstances/ra:LobSystemInstance[@Name='ResourceAutomotiveConsultingInstance']/ra:Properties/ra:Property[@Name ='rdbconnection Data Source']" Value="RAMGMOSSDEV" />
    <MergeSetting NodePath="/ra:LobSystem/ra:LobSystemInstances/ra:LobSystemInstance[@Name='ResourceAutomotiveConsultingInstance']/ra:Properties/ra:Property[@Name ='rdbconnection Initial Catalog']" Value="ResourceAutomotiveConsulting" />
    <MergeSetting NodePath="/ra:LobSystem/ra:LobSystemInstances/ra:LobSystemInstance[@Name='ResourceAutomotiveConsultingInstance']/ra:Properties/ra:Property[@Name ='rdbconnection User ID']" Value="bdcuser" />
    <MergeSetting NodePath="/ra:LobSystem/ra:LobSystemInstances/ra:LobSystemInstance[@Name='ResourceAutomotiveConsultingInstance']/ra:Properties/ra:Property[@Name ='rdbconnection Password']" Value="bdc123" />
  </Ssp>
</SspSettings>

Feature activated code  from Feature Receiver below reads the feature properties "ApplicationDefinitionFile", "SspSettingsFile" and gets the default Ssp name using stsadm -enumssp -default command (thanks to Ishai Sagi's blog post). Ssp settings are then read from configuration file and merged into application definition file before importing the application definition file into BDC.

   1: public override void FeatureActivated(SPFeatureReceiverProperties properties)
   2: {
   3:    if (Microsoft.Office.Server.ServerContext.Current != null)
   4:    {
   5:             string applicationDefinitionFile = ((SPFeatureProperty)properties.Feature.Properties["ApplicationDefinitionFile"]).Value;
   6:             string sspSettingsFile = ((SPFeatureProperty)properties.Feature.Properties["SspSettingsFile"]).Value;
   7:             string featureDirectory = properties.Definition.RootDirectory;
   8:             string sspName = DetermineSSPNameFromContext();
   9:  
  10:             //merge ssp settings to application definition file
  11:             string appdefFileAfterMerge =
  12:             MergeSSPSettingsToApplicationDefinitionFile(sspName, sspSettingsFile, applicationDefinitionFile, featureDirectory);
  13:  
  14:             //import the application definition file into business data catalog ;
  15:             ParseContext context = new ParseContext();
  16:             ApplicationRegistry.Instance.ImportPackage(appdefFileAfterMerge, context, Encoding.UTF8, PackageContents.Model |       PackageContents.LocalizedNames | PackageContents.Properties | PackageContents.Permissions);
  17:    }
  18: }

Install the feature using stsadm, Activate feature to SSP administration site. Feature should not be activated via stsadm reason for this is there won't be a ssp context available and feature receiver will not be able to determine which ssp settings to merge. You will need to go to site actions and click on site settings and click on site collection features and activate the feature from there.

MSDN Developer Conference
MSDN is bringing PDC to a city near you
check out this site and register, catch up on all the PDC action for less
 
 
SharePoint Blog Site: add post to socialbookmarking sites - javascript solution
So I Just recently signed up for an external WSS hosting and got my blog up and running. I wanted to have hyperlinks at the end of each blog post which would allow the reader to add it to facebook, digg or delicious sites. I searched online to see if there are any solutions and came across Mike Gannotti's blog post, this solution is really based on Mike's post I just made his solution better, also 3 images (facebook, digg, delicious) are downloaded from his site. So big shout goes out to Mike Gannotti.
 
If you are running sharepoint blog site here is how you can get this implemented to your sharepoint blog site
 
  • Download files here 
  • Extract the contents of the zip file and add it to a document library in your blog site
  • Add a formview web part to your sharepoint blog sites default.aspx page
  • Add a script tag to form view webpart with src referring to "SharePointBlogSocialBookMarkingutilities.js". This is a little technique I use to inject javascript into sharepoint pages without having to customize in SharePoint Designer. Here is sample markup from form view webpart in my site <script language="javascript" type="text/javascript" src="/Scripts/SharePointBlogSocialBookMarkingUtilities.js"></script>
  • Hide the formview web part so it's not visible in the page
Steps 3-5 need to be done for "Post.aspx" page as well. You also need to update the image urls for 3 images (facebook, digg, delicious) in the javascript file.
 
Enjoy! let me know if you have any issues getting this implemented.
PS: You can see this in action at the end of every blog post...
 
Data Layer Architecture Blueprint
Overview
data layer architecture blueprint is meant to provide architectural and process guidance to development teams building n-tier applications that connect to a backend relational database. This blueprint assumes you are using Microsoft SQL Server 2005 database, but that doesn't mean if your company is an Oracle shop you can't use it. You absolutely can as its completely tool independant and mostly architecture guidance.
 
Datalayer Architecture Blueprint
 
Key Design Goals
Following are the key design goals for this blueprint.
  • Control Access to Relational Tables, Data and other DDL components, appropriate change management procedures should be in place.
  • Logical seperation of Code & DDL components
  • Provide a sandbox for developers working in a team so that during development changes to stored procedure or table does not interfere with other developers in the team as well as break the application.
  • Improved security, when data access layer connection string is compromised, user can still perform operations that application allowed them to do and all data and DDL components are still protected.
Implementation Guidelines
Connect to SQL Server 2005 database and create three schemas.
  • ApplicationUsers Schema
  • Procedural Schema
  • Data Schema

Here is the T-SQL command to create Schemas in SQL Server 2005

CREATE SCHEMA ApplicationUsers AUTHORIZATION {user who will own the schema}

 CREATE SCHEMA Procedural AUTHORIZATION {user who will own the schema}

CREATE SCHEMA Data AUTHORIZATION {user who will own the schema}

Connect to the database as user that owns the "data" schema and create all the tables, constriants, triggers etc

Connect to the database as user that owns the "procedural" schema and compile all stored procedures, functions. Remember to request Database Administra