Ajax Webmethods, Javascript, and Anonymous Types… Booyah

As witnessed in this super awesome post I showed how to use a webmethod to get server side information with client side methods. (I know, I’m pretty sweet.) And in this one I had an example of filling a drop down list with a web method and javascript, though it was more about the anonymous method used. So what do I have now? Well a little thing about why I heart anonymous types.

What’s an anonymous type? Well it’s a type that built at compile time and requires no class file to create, but you probably have already used them if you’ve used Linq:

    var anonymous = from item in list
                    select new {
                                 Name = item.Name,
                                 Address = item.Address
                                };

And now you have a whole list of a new type that is created at compile time. Anyways, you might have been wondering why you would want these beyond linq use. Well that’s what I’m here for… that and making sure I give you a low point in your day so that things can only get better.

Now in the example from before, it was basically the idea of filling a drop down list without a postback and using a WebMethod. Now I showed the javascript needed, but I didn’t show you the web method itself.
Time to start!

        [System.Web.Services.WebMethod]
        [System.Web.Script.Services.ScriptMethod]
        public static Object GetUserList()
        {
            IList <User>userList;

            userList = LinqData.DataClasses.User
                           .GetUserList("");
            return userList
                      .Select(item => new { item.UserName, item.UserID })
                      .ToList();
        }

So there you have a method that gets some users (Waring: Actual method may vary) and you are creating a list of anonymous types that have UserName and UserID.

Now you may have noticed this:

    .Select(item => new { item.UserName, item.UserID })

Now why would I want to do that? Why can’t I just send a list of users? Well there’s nothing really stopping you from doing that, after all javascript will handle whatever you throw at it. Problem is: If you send an entire user, you’re sending everything. What if the user has an image on it? (Like an avatar) Maybe the user has a collection of addresses. Point is, that’s a lot to send out when you only need the two things. (Text and value for the dropdown list) The beauty of the anonymous types is you don’t need a new class file for the smaller version of the user thus allowing you to create a specific type that is only needed for this situation.

The nice thing to take from this is that you can easily create the bare minimum and really not sacrifice much. Why is that? Well you would think that the type is created for every user or maybe every time there is at least one instance running on the server. Fact is, the type itself is created at compile time so you don’t suffer that kind of pain. Beyond that, and I said this before, Javascript is more than capable of “reading” and “knowing” what the class has so you don’t have to worry about it needing some class off in some class file to send.

Now you could argue that you should have that class file and that it’s just good practice but I’m not convinced in this case. Mostly because this is a one time situation but, and yes it sounds funny to use “situation” again, situationally this is specific only to this instance… SITUATION

I suppose someone could argue that if I use other anonymous types elsewhere that use the same properties than I should make a new class file. There’s probably some truth to this, but on the other hand is it really necessary to go that far if you aren’t certain? I don’t know. But then again I’m fascinated by popcorn so you might not want to take my opinions seriously.

Javascript Anonymous Methods and How they help Ajax WebMethod

Ok so here’s what you’re trying to do:

You have a button and when it’s pressed you want to have it fill a drop down list without a postback. So your first thoughts are, “I like Mentos” followed by, “WebMethod” since you of course read this super awesome post. Now it might look like this:

        function GetUserList()
        {
            PageMethods.GetUserList(OnGetUserListComplete);
        }

        function OnGetUserListComplete(result)
        {
            var dropdownList = $get('dropdownListID');
            for (var i = 0; i < result.length; i++)
            {
                var item;
                item = document.createElement("option");
                item.text = result[i].UserName;
                item.value = result[i].UserID;
                dropdownList.options.add(item);
            }
        }

And GetUserList would be called on click. Fine and dandy, but this sort of bad since you’re hardcoding the id of the control. Meh. You look back at the method and see that there just isn’t a way to pass in a name, and if you didn’t you would be sooooo wrong it hurts. Shame on you. Good thing I’m here. The way you’re going to do this is to use an anonymous method. You see, as it is the PageMethod call needs a method to call post completion and that’s all it takes in. (Well not completely true, it can take in parameters for the server side method, but that’s not the point.) So you have to find a way for that PageMethod to call the method after completion AND make sure it has the list name with it.

        function GetUserList(dropdownList)
        {
            PageMethods.GetUserList(function(result) {
                 OnGetUserListComplete(result, dropdownList); });
        }

        function OnGetUserListComplete(result, dropdownList)
        {
            for (var i = 0; i < result.length; i++)
            {
                var item;
                item = document.createElement("option");
                item.text = result[i].UserName;
                item.value = result[i].UserID;
                dropdownList.options.add(item);
            }
        }

Ooo pretty tricky huh?

        PageMethods.GetUserList(function(result) {
                 OnGetUserListComplete(result, dropdownList); });

See what I did there, I created an anonymous method to be called on completion and in turn it calls the original (Though modified) OnGetUserListComplete method now. And you thought javascript sucked.

Call Server Side methods With Javascript in ASP.Net… Yeah Ajax

So I’ve been looking for something to match the simplicity of the old Ajax.dll WebMethods (The ability to asychronously call a method on a class from javascript) since the project was abandoned by the owner. A lot of what I saw before involved WebServices which wasn’t horrible, but I wanted Ajax.WebMethods. Come to find out, this simplicity exists in 3.5.

So let’s say I want to click on a div and have it’s innerHTML be filled with some string. Sounds like a completely viable situation for any money making business… Anyways, I could do some kind of post back and fill it, or I could use an update panel (Uhg) or I could use a Web Service or I could just bang my head on the desk and get the same level of satisfaction. But then came 3.5 and something wonderful. Take this page:

    public partial class Test : System.Web.UI.Page
    {
        [System.Web.Services.WebMethod]
        [System.Web.Script.Services.ScriptMethod]
        public static String GiveMeString()
        {
            return "hi";
        }
    }

See somethig weird? Yeah that’s the magic of the class file. All I need is:

  • A Static Method
  • The WebMethod Attribute
  • The ScriptMethod attribute
  • Optionally something to return, but for this example it’s not optional just like Burt Renold’s mustache

And now the page file is ready, but what about the markup? Well, that’s next, so glad you asked. First the javascript:

        function ShowString()
        {
            var test = $get('ShowThings');
            PageMethods.GiveMeString(OnGiveMeStringComplete);
        }

        function OnGiveMeStringComplete(result)
        {
            var test = $get('ShowThings');
            test.innerHTML = result;
        }

First method is the method to call. The PageMethods object will allow the use of the class method that was created. The parameter being sent in is actually the method needing to be called when the server side call is complete. With that in mind, guess what the second method is… No, not ice cream. It’s the method called when the server call is compete. As you can see, I am simply changing the innerHTML of a div.

    <form id="form1" runat="server">
        <asp:ScriptManager ID="smMain" runat="server" EnablePageMethods="true" />
        <div id="ShowThings" style="background-color:Yellow;height:20px;width:20px;"
          onclick="ShowString()"></div>
    </form>

And there you have the markup. ScriptManager is a must in this case, but that’s pretty standard when dealing with Ajax in asp.net. The only other thing of note is the method call on the div’s onClick. Beyond that, it’s ready to go. And if you were to make this example yourself and click on the div, you will get a ‘hi’ string in it on the first click. Amazing.

Return False from a ScriptControl method and why I hate Firefox…

I have to admit that it might be IE that is wrong, but I don’t know. That and I do kind of hate Firefox so I’ll stand by the title anyhow.

This is a little off the current beaten path, but does deal with the current ScriptControl theme so I thought I’d put it in here.

Here’s the problem: You have a script control, a button, and want to have the person confirm before it’s allowed to postback. Easy right? If this were the non script control way you would do this:

Javascript:

    function ReturnFalse()
    {
      var confirmed = confirm('Is there anyone more awesomer that Sean?');
      return confirmed;
    }

Markup:

  <asp:Button ID="whoCares" runat="server" OnClientClick="return ReturnFalse();" >

Class Stuff:

  whoCares.Click += whoCares_Click;
  ...
  private void whoCares_Click(object sender, EventArgs e)
  {
    throw new NotImplementedException();
  }

Basically what I’ve done is made it so that if it doesn’t return false, an exception is thrown. Easy test. Works in both browsers right? Brilliant.

Now for the script control:

  handleLnkDeleteButtonClick: function(e)
  {
      var confirmed = confirm('Is there anyone more awesomer that Sean?');
      return confirmed;
  },

 initialize: function()
 {
    this._lnkDeleteButton = $get(this._lnkDeleteButtonID);
    this._lnkDeleteButton.idpicker = this;

    //HOOK BEGINS HERE
    this._lnkDeleteButtonClick = Function.createDelegate(this, this.handleLnkDeleteButtonClick);
    $addHandler(this._lnkDeleteButton, "click", this._lnkDeleteButtonClick);
    //END HOOK HERE

    NDI.WebControls.Client.PersonalMessageTypePicker.callBaseMethod(this, 'initialize');
},

Now that looks ok right? The method pops up the confirmation button alert dialogue thingy and returns the answer but guess what, you’re wrong. So wrong. In IE this works but in Firefox, sorry no deal. Firefox will ignore anything returned if the “return” keyword is not in the markup. Well from here there’s no real markup so how the hell would I do that? Well yes Virginia there is a Santa Clause and he lives in e.preventDefault();

It’s actually really simple, one small change in the handling method. You replace return X with e.preventDefault();

  handleLnkDeleteButtonClick: function(e)
  {
    var confirmed = confirm('This will delete the currery Message category
      and move all messages to the Oprhan cataegory.  Allow?');
    if (!confirmed)
    {
        e.preventDefault();
    }
  },

And now it works. Yes you can thank me with large donations of money or cheese.

Creating Script Controls And Love (ASP.Net ScriptControl)

[Part One] [Part Two] [Part Three] [Part Four] [Part Five]

So this will be the first of a couple posts having to do with Script Controls, the Ajax Control Tool Kit AutoComplete control, and Javascript. Now to get started, what’s a script control?

I’m glad you asked. Basically have you ever created a user control that required Javascript to go along with it? What if the control was in another assembly? Oh woe is you. Well you could require the .js file to be placed in the web project and included on the page. Meh. OR you could use a script control YAY! How does that help? Well it allows you to “attach” a javascript file to a control in a class library, no includes needed. Not only that, but you can pass values from the control to the client and use them with Javascript. (This includes ids of controls in the control.)

So what’s needed? Well…
1. Create a class library, Call it Test and make the default Namespace Test.Examples

2. Create a folder to hold the class file and the JavaScript file. Let’s call it ScriptControlTemplate for now.

2. Create the control class file and the needed JavaScript file. Call them both ScriptControlExample. (For right now it will be easier if they have the same name but they don’t have to be.)

3. Right click the JavaScript Files -< Properties -< Build Action: Embedded Resource

4. Go to the Properties folder in the class Library and open the AssemblyInfo.cs. Add this line:

[assembly: WebResourceAttribute
    ("Test.ScriptControlTemplate.ScriptControlExample.js", "text/javascript")]

Now you might notice something, that almost looks like the actual folder location and it kind of is. In order for this line to work, it has to match the folder location like when Visual Studios creates a Namespace automatically. It uses the directory name as the final part of the namespace. Although to note, the Namespace of the class DOES NOT have to match this. It just has to reflect the directory structure of where the .js file is.

Ok so now we have a blank .cs file and a blank .js file. Woo hoo. Now what? Well first you need to have the class inherit from System.Web.UI.ScriptControl and override two protected methods

    public class ScriptControlExample : ScriptControl , INamingContainer
    {
        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            ScriptControlDescriptor desc =
                 new ScriptControlDescriptor("Test.Examples.Client.ScriptControlExample", ClientID);
        }

        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
          return new ScriptReference[] {
              new ScriptReference("Test.Examples.ScriptControlTemplate.ScriptControlExample.js", "Test.Examples") };

        }
    }

Ok so I cheated a little and put in two lines that you will need anyhow. I figured it would save some time, mainly mine. Cause let’s face it, I don’t really care about yours.

The first method GetScriptDescriptors is where we will be putting any values we want to send to the Client. The second just tells the system where the JavaScript file is to load. For now you won’t be doing anything with the second.

Ok now on to the Javascript file. Basically you have some cannon methods to add just to get the thing to work, and I’ll be honest: It’s extremely complicated and you probably won’t be smart enough to figure it out.

//Set the namespace
if (Type)
{
    Type.registerNamespace("Test.Examples.Client");
}

//Won't be doing much with this for the examples I have
Test.Examples.Client.ScriptControlExample = function(element)
{
    Test.Examples.Client.ScriptControlExample.initializeBase(this, [element]);
}

//This is where you basically define the class
Test.Examples.Client.ScriptControlExample.prototype =
{
    //Where you want to place constructor like code
    initialize: function()
    {
        Test.Examples.Client.ScriptControlExample.callBaseMethod(this, 'initialize');
    },

    //Remove events and such here
    dispose: function()
    {
        Test.Examples.Client.ScriptControlExample.callBaseMethod(this, 'dispose');
    }
}
Test.Examples.Client.ScriptControlExample.registerClass('Test.Examples.Client.ScriptControlExample',
   Sys.UI.Control);

Phew that was complicated right?

Ok so now you have what you need to create a script control. Run it and well nothing will really happen except you shouldn’t get errors.

Now just create a new page in a web application (Or project if you’re a loser) and just do this realy quick:

<%@ Register Assembly="Test.Examples"
    Namespace="Test.Examples.ScriptControlTemplate" TagPrefix="test" %>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="smMain" runat="server" />
        <test:ScriptControlExample ID="sceTest" runat="server" />
    </div>
    </form>
</body>
</html>

Run it and…..NOTHING! Surprise! Actually there is something, just nothing visual yet. Next post will get to that. Sucker.

One thing you can take away from this: A drinking game. Take a drink everytime you see the word ‘Ok’ in this post. I dare you.

UpdatePanel and UserControl Events

So on the funnest programmin’ site evar someone had asked how to allow an UpdatePanel on a page handle an event of a UserControl. So here’s the situation:

Let’s say you have a UserControl and on that UserControl you have a DropDownList. I know, this is getting complex, but just bare with me. Now imagine, if you will, you want the Parent page’s UpdatePanel to trigger off of the mentioned DropDownList. As it stands, this isn’t going to happen. Why? Because the Parent really can’t capture the event firing on the control since it is localized to the UserControl. What to do? Easy, just pass the event on.

    public partial class CatchMyEvent : UserControl
    {
        public delegate void ChangedIndex(object sender, EventArgs e);
        public event ChangedIndex SelectedIndexChanged;

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            dropDownListThrow.SelectedIndexChanged +=
               new EventHandler(dropDownListThrow_SelectedIndexChanged);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
        }

        public void dropDownListThrow_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(SelectedIndexChanged != null)
            {
                SelectedIndexChanged(sender, e);
            }
        }
    }

As you can see, all I’ve done

  1. Created a PUBLIC delegate and event that has the same signature as the SelectedIndexChanged event
  2. Captured the SelectedIndexChanged event in the UserControl
  3. Fired off the created event

It’s like I’m just handing off the event firing to the next guy, the next guy being the Parent page in this instance. Now the code behind for the Parent page is really simple:

    public partial class Catcher : Page
    {
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            catchMyEventMain.SelectedIndexChanged += dropDownListThrow_SelectedIndexChanged;
        }

        public void dropDownListThrow_SelectedIndexChanged(object sender, EventArgs e)
        {
            labelSelectedValue.Text = ((DropDownList)sender).SelectedItem.Text;
        }
    }

As you can see, the Parent now is also looking for the DropDownList SelectedIndexChanged event to fire, except we both know that it’s not the official SelectedIndexChanged event, but an event that is merely passing on the information. Now for the Parent page markup:

    <asp:ScriptManager ID="smMain" runat="server" />
    <asp:UpdatePanel ID="upMain" runat="server" >
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="catchMyEventMain" EventName="SelectedIndexChanged" />
        </Triggers>
        <ContentTemplate>
            <uc1:CatchMyEvent ID="catchMyEventMain" runat="server" />
            <asp:Label ID="labelSelectedValue" runat="server" />
         </ContentTemplate>
    </asp:UpdatePanel>

So in all this will update a label’s text on the Parent page to equal that of the SelectedItem.Value of the DropDownList of the UserControl. And all without the annoying page refresh.

Just remember, the DropDownList has to have AutoPostback set to true. Don’t be dumb like me and forget that when testing.