Second Life of a Hungarian SharePoint Geek

March 3, 2010

AJAX-enabling the TaxonomyWebTaggingControl

Filed under: AJAX, Reflection, SP 2010, Taxonomies — Tags: , , , — Peter Holpar @ 04:37

If you need to use the TaxonomyWebTaggingControl on a complex UI and would not like to refresh all the page if you have to change only the part where the taxonomy control is, you may try to use AJAX UpdatePanel as shown in the Visual Web Part code below.

  1. <%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
  2. <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  3. <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  4. <%@ Register Tagprefix="Taxonomy" Namespace="Microsoft.SharePoint.Taxonomy" Assembly="Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  5. <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  6. <%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
  7. <%@ Import Namespace="Microsoft.SharePoint" %>
  8. <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  9. <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="VisualWebPart1UserControl.ascx.cs" Inherits="TestWebPart.VisualWebPart1.VisualWebPart1UserControl" %>
  10.  
  11. <asp:UpdatePanel ID="UpdatePanel1" UpdateMode="Always" RenderMode="Block" runat="server">
  12. <ContentTemplate>
  13. <Taxonomy:TaxonomyWebTaggingControl ID="TaxonomyControl" runat="server" />
  14.  
  15.  
  16. <p><asp:LinkButton ID="PostbackButton" OnClick="PostbackButton_OnClick" runat="server">Postback</asp:LinkButton></p>
  17.  
  18.  
  19. </ContentTemplate>
  20. </asp:UpdatePanel>

Of course, replace term store / group / set names to match your environment.

  1. using System;
  2. using System.Web.UI;
  3. using System.Web.UI.WebControls;
  4. using System.Web.UI.WebControls.WebParts;
  5. using Microsoft.SharePoint.Taxonomy;
  6. using Microsoft.SharePoint;
  7.  
  8. namespace TestWebPart.VisualWebPart1
  9. {
  10.     public partial class VisualWebPart1UserControl : UserControl
  11.     {
  12.         protected void Page_Load(object sender, EventArgs e)
  13.         {
  14.                 SPContext context = SPContext.Current;
  15.                 SPSite site = context.Site;
  16.                 TaxonomySession session = new TaxonomySession(site);
  17.                 TermStore termStore = session.TermStores["Metadata"];
  18.                 Group group = termStore.Groups["Test"];
  19.                 TermSet productsTermSet = group.TermSets["Products"];
  20.  
  21.                 TaxonomyControl.SspId.Add(termStore.Id);
  22.                 TaxonomyControl.TermSetId.Add(productsTermSet.Id);
  23.                 TaxonomyControl.IsAddTerms = true;
  24.                 TaxonomyControl.AllowFillIn = true;
  25.                 TaxonomyControl.IsMulti = true;
  26.         }
  27.  
  28.         protected void PostbackButton_OnClick(object sender, EventArgs e)
  29.         {
  30.             // do nothing
  31.         }
  32.     }
  33. }

On the first page load everything seems to be OK.

image

But when you click on the Postback button the taxonomy control seems to be lost as shown below.

image

To understand why it happens you should know that the TaxonomyWebTaggingControl is rendered on server side as a hidden field and a DIV element. Text field, icon added using client side scripts, as well other initialization steps required to the full functionality.

The client side script is produced by the private getOnloadJavascript method of the TaxonomyWebTaggingControl. To enable the taxonomy functionality, we should run first part of the script after the partial-page update. We can use the AJAX Sys.WebForms.PageRequestManager endRequest event to catch and inject our JavaScript to handle this requirement.

The code below shows you how to get the script we need using Reflection and register it on the page for re-initialization after the update happens.

  1. using System;
  2. using System.Web.UI;
  3. using System.Web.UI.WebControls;
  4. using System.Web.UI.WebControls.WebParts;
  5. using Microsoft.SharePoint.Taxonomy;
  6. using Microsoft.SharePoint;
  7. using Microsoft.SharePoint.Utilities;
  8. using System.Reflection;
  9. using System.Text;
  10.  
  11. namespace TestWebPart.VisualWebPart1
  12. {
  13.     public partial class VisualWebPart1UserControl : UserControl
  14.     {
  15.         protected void Page_Load(object sender, EventArgs e)
  16.         {
  17.                 SPContext context = SPContext.Current;
  18.                 SPSite site = context.Site;
  19.                 TaxonomySession session = new TaxonomySession(site);
  20.                 TermStore termStore = session.TermStores["Metadata"];
  21.                 Group group = termStore.Groups["Test"];
  22.                 TermSet productsTermSet = group.TermSets["Products"];
  23.  
  24.                 TaxonomyControl.SspId.Add(termStore.Id);
  25.                 TaxonomyControl.TermSetId.Add(productsTermSet.Id);
  26.                 TaxonomyControl.IsAddTerms = true;
  27.                 TaxonomyControl.AllowFillIn = true;
  28.                 TaxonomyControl.IsMulti = true;
  29.  
  30.                 // register the client script for taxonomy control initialization
  31.                 String key = "TaxonomyWebTaggingAjaxIncludeOnce";
  32.                 if (!this.Page.ClientScript.IsClientScriptBlockRegistered(base.GetType(), key))
  33.                 {
  34.  
  35.                     this.Page.ClientScript.RegisterClientScriptBlock(base.GetType(), key, GetReloadJavaScript(TaxonomyControl), true);
  36.                 }
  37.         }
  38.  
  39.         protected void PostbackButton_OnClick(object sender, EventArgs e)
  40.         {
  41.             // do nothing
  42.         }
  43.  
  44.         private string GetReloadJavaScript(TaxonomyWebTaggingControl taxonomyControl)
  45.         {
  46.             String script = String.Empty;
  47.  
  48.             String containerId = SPEncode.ScriptEncode(taxonomyControl.Controls[1].ClientID);
  49.  
  50.             Type type_TaxonomyWebTaggingControl = typeof(TaxonomyWebTaggingControl);
  51.  
  52.             MethodInfo mi_getOnloadJavascript = type_TaxonomyWebTaggingControl.GetMethod("getOnloadJavascript", BindingFlags.NonPublic | BindingFlags.Instance);
  53.             String fullScript = (String)mi_getOnloadJavascript.Invoke(taxonomyControl, null);
  54.             int pos = fullScript.IndexOf(String.Format("function {0}_load()", containerId));
  55.  
  56.             if (pos > –1)
  57.             {
  58.                 StringBuilder builder = new StringBuilder();
  59.                 builder.Append("var myPrm = Sys.WebForms.PageRequestManager.getInstance();");
  60.                 builder.Append("myPrm.add_endRequest(EndRequest);");
  61.                 builder.Append("function EndRequest(sender, args)");
  62.                 builder.Append("{");
  63.                 // we get te first part of the script needed to initialization
  64.                 // we start from pos 1, because we don't need the leading '{'
  65.                 builder.Append(fullScript.Substring(1, pos – 1));
  66.                 builder.Append("Microsoft.SharePoint.Taxonomy.ScriptForWebTaggingUI.onLoad('");
  67.                 builder.Append(containerId);
  68.                 builder.Append("');");
  69.                 builder.Append("}}");
  70.  
  71.                 script = builder.ToString();
  72.             }
  73.  
  74.             return script;
  75.         }
  76.     }
  77. }

Advertisements

10 Comments »

  1. Very helpful, thank you!

    Comment by hhtech1 — March 8, 2010 @ 14:34

  2. Hi – Thank you for posting this. There are very few resources on TaxonomyWebTaggingControl and finding this on your site is really a big help. I just have a few questions.

    1. I tried your code above but I am getting an error. It doesn’t seem like type_TaxonomyWebTaggingControl has a GetMethod property that I can use. Did I miss something in your code?

    http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.taxonomy.taxonomywebtaggingcontrol_members%28v=office.14%29.aspx

    2. Is there a way to inject back the getOnloadJavascript via add_endRequest() of Sys.WebForms.PageRequestManager.getInstance() (in short, client-side) 😀 ?

    Your response will be really really helpful. Thanks in advance!

    Cheers!

    Comment by Stumped1 — May 4, 2010 @ 15:40

    • Hi Stumped1,

      1. As you can see, the type of type_axonomyWebTaggingControl object is defined as System.Type, not TaxonomyWebTaggingControl (http://msdn.microsoft.com/en-us/library/system.type.aspx). The Type class has several overloads of the GetMethod method (not property!) you can use. If you got error it may be (but not sure) the result running the code on the final bits, as the article was written for beta, and I have not checked the working on the release yet. You wrote you are getting an error, but it does not help much resolving the issue without knowing what kind of error you get exactly and in which line of code (stack trace, etc).

      2. You can inject back JavaScript using client side scripts generated on server side. That is what I’m just doing here. You cannot use Sys.WebForms.PageRequestManager.getInstance() method from client side code, as it is a server side object method in AJAX, and you cannot get the code of the getOnloadJavascript method from client side code unless you hardcode it or create a web service or something like that and call that service from client side code. But in ASP.NET AJAX, it’s the standard way to use server side objects to generate the client content. I might not understand the point of your question.

      Peter

      Comment by pholpar — May 5, 2010 @ 06:24

      • Okay. Sorry for the confusion. Another question, will this work in a partial postback? I was able to make the code work but I still can’t make the control reappear after the partial postback.

        I trigger a partial postback using the command below and the TaxonomyWebTaggingControl still disappears.

        __doPostBack(‘updatePanel1’, ”);

        Comment by Stumped1 — May 6, 2010 @ 03:19

  3. Just found this article, it illuminates a problem I have been fighting for several days. Thanks! I do have a minor problem, however. While the taxonomy field control retains it presence on the form, the connection to the metadata store is lost. I am using basically the same connection code you are in PageLoad. can you provide any insight?

    Comment by Tom Hill — April 9, 2012 @ 13:39

  4. great code thank you

    Comment by Jake — August 24, 2012 @ 22:02

  5. Great help… Thanks a lot for sharing this..

    Comment by Dhileep — November 23, 2012 @ 06:15

  6. Thanks again for you great post. When i use the same code this is working for only one taxonomy control. If i have more than one taxonomy controls in the page this is not working for all the controls. I dont have enough knowledge in scripting, can you pleas help me how to get this working for all the taxonomy controls.

    Comment by Dhileep — November 23, 2012 @ 13:57

  7. One of my colleague was using this method, but I found some issue in IE8, get error message: ‘Sys’ is undefined
    Instead of using “RegisterClientScriptBlock”, using “RegisterStartupScript” to avoid this error:

    if (!this.Page.ClientScript.IsStartupScriptRegistered(base.GetType(), key))
    {
    this.Page.ClientScript.RegisterStartupScript(base.GetType(), key, GetReloadJavaScript(TaxonomyControl), true);
    }

    Comment by Brandon Wang — November 24, 2012 @ 17:55

  8. Thanks for the great post. It really saved a lot of my time.

    Comment by iGary — February 14, 2014 @ 12:14


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: