<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Marc Dormey &#187; mvc</title>
	<atom:link href="http://www.marcdormey.com/index.php/tags/mvc/feed" rel="self" type="application/rss+xml" />
	<link>http://www.marcdormey.com</link>
	<description>Software Finds, Programming Tutorials and Gadget Reviews</description>
	<lastBuildDate>Tue, 20 Jul 2010 14:52:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ASP.NET MVC JQuery ScriptManager</title>
		<link>http://www.marcdormey.com/index.php/archives/asp-net-mvc-jquery-scriptmanager</link>
		<comments>http://www.marcdormey.com/index.php/archives/asp-net-mvc-jquery-scriptmanager#comments</comments>
		<pubDate>Fri, 23 Oct 2009 11:19:54 +0000</pubDate>
		<dc:creator>Marcel</dc:creator>
				<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[asp.net mvc]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[scriptmanager]]></category>

		<guid isPermaLink="false">http://www.marcdormey.com/?p=250</guid>
		<description><![CDATA[As I was developing a CMS system for a client, we had a very unique scenario (well maybe not that unique) where we had custom &#8220;parts&#8221; which you could add to a page. The &#8220;parts&#8221; were highly customisable, thus you could have 3 instances of the same &#8220;part&#8221; on one page. The html and javascript [...]]]></description>
			<content:encoded><![CDATA[<p>As I was developing a CMS system for a client, we had a very unique scenario (well maybe not that unique) where we had custom &#8220;parts&#8221; which you could add to a page. The &#8220;parts&#8221; were highly customisable, thus you could have 3 instances of the same &#8220;part&#8221; on one page. The html and javascript rendered by the part would conflict with each other, because they had the same id&#8217;s and registered events.</p>
<p>I needed something similar to the old ASP.NET Script manager and the way that old ASP.NET used the &#8220;clientId&#8221; instead of the &#8220;htmlId&#8221; when dealing with html objects. The &#8220;clientId&#8221; was a generated unique key that prevented duplicated user controls conflicting with one another.</p>
<p>I found quite a few implementations of ScriptManager (<a href="http://pietschsoft.com/post/2009/08/13/Simple-ScriptManager-for-ASPNET-MVC.aspx">http://pietschsoft.com/post/2009/08/13/Simple-ScriptManager-for-ASPNET-MVC.aspx</a>, <a href="http://aspmvccombine.codeplex.com/">http://aspmvccombine.codeplex.com/</a>) for MVC, but none of them were solving my unique &#8220;htmlId&#8221; problem. If you are looking for a ScriptManager for MVC, then the two solutions I provided would be more than enough. If, however, you are in a similar situation as I am with the html controls, please read on&#8230;</p>
<p>I decided to combine knowledge obtained from the two ScriptManager implementations, and create my own light-weight solution addressing both problems.<br />
Because I wanted the usage of this to be very simple, I created a fluent interface which I can use in all my parts&#8230;</p>
<p>This is what the end result looks like:</p>
<pre class="brush:csharp">&lt;% Html.ScriptManager()
     .CreateClientScript(GetUniqueId())
       .AddParam("SelectId", GetUniqueId("selectList"))
       .AddParam("SourceUrl", Url.Action("Index", "Person"))
       .Ready(() =&gt; {%&gt;
            $.getJSON(params.SourceUrl, function(result) {
                $.populate_combobox(result, params.SelectId);
            });
      &lt;%});%&gt;

&lt;% Html.ScriptManager().AddStaticMethod("populate_combobox", () =&gt;{ %&gt;
    jQuery.populate_combobox = function(data, selectId) {
        $.each(data, function() {
            var option = new Option(this.text, this.value);
            var dropdownList = $(selectId)[0];
            if ($.browser.msie) {
                dropdownList.add(option);
            } else {
                dropdownList.add(option, null);
            }
        });
    }
&lt;%});%&gt;

&lt;div id="&lt;%=GetUniqueId() %&gt;_part"&gt;
 &lt;select id="&lt;%=GetUniqueId("selectList") %&gt;"&gt;&lt;/select&gt;
&lt;/div&gt;</pre>
<p>My &#8220;GetUniqueId()&#8221; function returns a combination of the PartId, PageId, but you can replace this with anything you fancy.<br />
The javascript that gets generated by this is:</p>
<pre class="brush:js">var ContentPart_AboutPage_82 = {
        Init: function(params) {
            $.getJSON(params.SourceUrl, function(result) {
                $.populate_combobox(result, params.SelectId);
            });
        }
}
var ContentPart_AboutPage_83 = {
        Init: function(params) {
            $.getJSON(params.SourceUrl, function(result) {
                $.populate_combobox(result, params.SelectId);
            });
       }
}
var ContentPart_AboutPage_84 = {
        Init: function(params) {
            $.getJSON(params.SourceUrl, function(result) {
                $.populate_combobox(result, params.SelectId);
            });
       }
}
$(document).ready(function() {
    ContentPart_AboutPage_82.Init({
       SelectId:'ContentPart_AboutPage_82_selectList',
       SourceUrl:'/Person'
    });
    ContentPart_AboutPage_83.Init({
       SelectId:'ContentPart_AboutPage_83_selectList',
       SourceUrl:'/Person'
    });
    ContentPart_AboutPage_84.Init({
       SelectId:'ContentPart_AboutPage_84_selectList',
       SourceUrl:'/Person'
    });
});

    jQuery.populate_combobox = function(data, selectId) {
        $.each(data, function() {
        var option = new Option(this.text, this.value);
        var dropdownList = $(selectId)[0];
        if ($.browser.msie) {
            dropdownList.add(option);
        } else {
            dropdownList.add(option, null);
        }
      });
    }</pre>
<p>Update: I have gone even further and added the concept of &#8220;SharedVariables&#8221; to the ScriptManager where the &#8220;SourceUrl&#8221; above and even the Json request is fired only once!</p>
<p>Here is my ScriptManager Class:</p>
<pre class="brush:csharp">public class ScriptManager
{
    private readonly HtmlHelper _helper;

    public IDictionary&lt;string, ClientScript&gt; ClientScripts
    {
       get
       {
          if (_helper.ViewContext.HttpContext.Items["ClientScripts"] == null)
          _helper.ViewContext.HttpContext.Items["ClientScripts"] = new Dictionary&lt;string, ClientScript&gt;();

          return (IDictionary&lt;string, ClientScript&gt;)_helper.ViewContext.HttpContext.Items["ClientScripts"];
       }
    }

    public IDictionary&lt;string, Action&gt; Methods
    {
      get
      {
         if (_helper.ViewContext.HttpContext.Items["ScriptMethods"] == null)
         _helper.ViewContext.HttpContext.Items["ScriptMethods"] = new Dictionary&lt;string, Action&gt;();

         return (IDictionary&lt;string, Action&gt;) _helper.ViewContext.HttpContext.Items["ScriptMethods"];
      }
    }

   public ScriptManager(HtmlHelper helper)
   {
       _helper = helper;
   }

   public ClientScript CreateClientScript(string key)
   {
      if(!ClientScripts.ContainsKey(key))
       ClientScripts.Add(key, new ClientScript());

      return ClientScripts[key];
   }

   public ScriptManager AddStaticMethod(string key, Action javascript)
   {
     if(!Methods.ContainsKey(key))
       Methods.Add(key, javascript);

     return this;
   }

   public void Render()
   {
     TextWriter writer = _helper.ViewContext.HttpContext.Response.Output;
     writer.WriteLine("&lt;script type=\"text/javascript\"&gt;");

     foreach (var clientScript in ClientScripts.Keys)
     {
       writer.WriteLine("var " + clientScript + " = {");
       writer.WriteLine("        Init: function(params) {");
       ClientScripts[clientScript].Value();
       writer.WriteLine("        }");
       writer.WriteLine("}");
     }

     writer.WriteLine("$(document).ready(function() {");
     foreach(var clientScript in ClientScripts.Keys)
     {
       var client = ClientScripts[clientScript];
       writer.WriteLine("    " + clientScript + ".Init({");
       foreach (var param in client.Params)
         writer.WriteLine("       {0}:'{1}'{2}", param.Key, param.Value, IsLast(client.Params, param.Key) ? string.Empty : ",");
         writer.WriteLine("    });");
       }
     writer.WriteLine("});");
     foreach(var method in Methods.Values)
       method();
     writer.WriteLine("&lt;/script&gt;");
   }

   private static bool IsLast(IDictionary&lt;string, string&gt; parameters, string key)
   {
     var keys = parameters.Keys.ToList();
     return keys.Count &gt; 0 &amp;&amp; keys[keys.Count-1] == key;
   }
}</pre>
<p>Here is the ClientScript class:</p>
<pre class="brush:csharp">public class ClientScript
{
   private readonly IDictionary&lt;string, string&gt; _parameters = new Dictionary&lt;string, string&gt;();
   private Action _script;

   public IDictionary&lt;string, string&gt; Params
   {
     get { return _parameters; }
   }

   public ClientScript AddParam(string key, string value)
   {
     Params.Add(key, value);
     return this;
   }

   public ClientScript Ready(Action script)
   {
     _script = script;
     return this;
   }

   public Action Value
   {
     get
     {
       return _script;
     }
   }
}</pre>
<p>Here is my extension method:</p>
<pre class="brush:csharp">public static ScriptManager ScriptManager(this HtmlHelper helper)
{
    return new ScriptManager(helper);
}</pre>
<p>And then you only need to add this at the end of your master page:</p>
<pre class="brush:csharp">&lt;% Html.ScriptManager().Render(); %&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.marcdormey.com/index.php/archives/asp-net-mvc-jquery-scriptmanager/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
