Thursday, August 15, 2013

InfoPath 2010: Populating a dropdown with SharePoint Metadata Termstore

In one of my projects, I had to build an InfoPath 2010 form needs to populate a couple of dropdown lists with values from the SharePoint metadata term store.

In a nutshell, this is how I managed to get it working:
Using PowerShell, I extracted the IDs of the Metadata service name, and the IDs of the term set name.

$col = Get-SPSite http://sharepoint
#Get TermStore ID
$taxonomySession = Get-SPTaxonomySession -site $col
$termStore = $taxonomySession.TermStores["Managed Metadata Service"]
$termStore.Id

#Get TermSet ID
$termStoreGroup = $termStore.Groups["Departments"]
$termSet.Id



Following that, I created a (repeating) group called tblDept in InfoPath. You can do so by going to the Fields toolbar, right click the top level element and choose Add.



Next, create a new data connection called GetDepartments to receive data from the site's TaxonomyService.asmx web services. You can get it from /_vti_bin/TaxonomyService.asmx.

In the next window, populate the term store id and term set ids like below:

By triggering this data connection to retrieve data each time the form loads, the resulting term set will be stored in an XML for later use.

Now add code-behind to your InfoPath form by clicking on the Developer tab - Loading Event button. Sample of code:

      public void FormEvents_Loading(object sender, LoadingEventArgs e)  
     {  
       XPathNavigator mainNav = this.MainDataSource.CreateNavigator();  
       // Retrieve list of Departments from Content Type Hub  
       populateDropdown(  
         mainNav, "/my:myFields/my:tblDept/my:Dept", "GetDepartments",  
         "Dept", "DeptValue", "DeptGuid", "/my:myFields/my:tblDept"  
       );  
     }  

The populateDropdown function will parse the XML to get the Term Set labels, and add them as a new element called Dept into tblDept.

      private void populateDropdown(  
       XPathNavigator nav, string fieldXPath, string dataSourceName,   
       string fieldName, string valueLabel, string guidLabel, string groupXPath  
       )  
     {  
       cleanupDropdown(nav, fieldXPath);  
       XPathNavigator termSetNav = this.DataSources[dataSourceName].CreateNavigator();  
       // as we're calling the same web service function for each term set,   
       // the xpath stays the same  
       string xPath = "/dfs:myFields/dfs:dataFields/ns1:GetTermSetsResponse/ns1:GetTermSetsResult";  
       XPathNavigator nodeNav = termSetNav.SelectSingleNode(xPath, this.NamespaceManager);  
       string resultXML = nodeNav.Value.ToString();  
       XmlDocument termSetXML = new XmlDocument();  
       termSetXML.LoadXml(resultXML);  
       XmlNodeList terms = termSetXML.GetElementsByTagName("T");  
       foreach (XmlNode term in terms)  
       {  
         XmlNode v = term.SelectSingleNode("LS/TL");  
         string termValue = v.Attributes["a32"].Value;  
         string termGuid = term.Attributes["a9"].Value;  
         if (!string.IsNullOrEmpty(termValue))  
           addDropdown(fieldName, termValue, valueLabel, termGuid, guidLabel, groupXPath, nav);  
       }  
     }  

Prior to adding the dropdown, I make a cleanUPDropdown call to clear tblDept of any existing value.

     private void cleanupDropdown(XPathNavigator nav, string xPath)  
     {  
       XPathNodeIterator rows = nav.Select(xPath, NamespaceManager);  
       // remove selected row(s) from table  
       for (int i = rows.Count; i > 0; i--)  
       {  
         XPathNavigator delRow = nav.SelectSingleNode(xPath + "[" + i + "]", NamespaceManager);  
         if (delRow != null)  
           delRow.DeleteSelf();  
       }  

Next, I loop through each term label and call addDropdown.

     private void addDropdown(string groupName, string value, string valueLabel,   
       string guid, string guidLabel, string xPath, XPathNavigator nav)  
     {  
       XmlDocument doc = new XmlDocument();  
       XmlNode group = doc.CreateElement(groupName, NamespaceManager.LookupNamespace("my"));  
       XmlNode field = doc.CreateElement(valueLabel, NamespaceManager.LookupNamespace("my"));  
       XmlNode node = group.AppendChild(field);  
       node.InnerText = value;  
       XmlNode fieldGuid = doc.CreateElement(guidLabel, NamespaceManager.LookupNamespace("my"));  
       XmlNode guidNode = group.AppendChild(fieldGuid);  
       guidNode.InnerText = guid;  
       doc.AppendChild(group);  
       nav.SelectSingleNode(  
        xPath,  
        NamespaceManager).AppendChild(doc.DocumentElement.CreateNavigator());  
     }    }  

Finally, add a Drop-Down List Box to the InfoPath form and map the entries to tblDept


It might seem complicated but that's part of the fun!
Related Posts Plugin for WordPress, Blogger...