The Ever-Useful $get and $find ASP.NET AJAX Shortcut Functions

If you have been working with Microsoft's ASP.NET AJAX components, you are probably very familiar with the $get and $find JavaScript shortcut functions.  If not, here is a quick refresher.

$get

Overview

$get can be used as shorthand for the document.getElementById and element.getElementById functions.  The $get shortcut function points to the Sys.UI.DomElement.getElementById JavaScript function which is defined as part of the ASP.NET AJAX client side library (which means you will need to include a ScriptManager on the page to be able to use it).  $get accepts two parameters, the first is the ID of the DOM element you want to retrieve, the second is the parent element of where the search starts.  The second parameter is optional and when it is not supplied defaults to the document element.  Here is the official API reference.

If you happen to step into $get during a debugging session you will find that it basically comes down to the following function ...

    function get(id, element) {
        //  validation code that was removed

        if (!element) return document.getElementById(id);
        if (element.getElementById) return element.getElementById(id);

        //  manual DOM walk that was removed ...
    } 

Sample Usage 1

Here is a very simple sample page that contains a single line of text along with three buttons.  When you click on the buttons, the text changes color. 

    

The html for this page defines a JavaScript function that is wired to handle each of the button onclick events.  Inside the event handler, the $get shortcut is used to look up the div element that contains the text and set its color style to the appropriate color.  Here is the markup for this page ...

<form runat="server">
    <asp:ScriptManager runat="server" />
    <script type="text/javascript">
        
        function changeColor(color){
            //  fetch the div
            var div = $get('div');
            
            //  set the color to the provided value
            div.style.color = color;
        }    
        
    </script>
    <div id="div">Some sample text.  You can change the color of the text by clicking the buttons</div>
    <input id="btnBlue" type="button" value="Blue" onclick="changeColor('blue');" />
    <input id="btnGreen" type="button" value="Green" onclick="changeColor('green');" />
    <input id="btnRed" type="button" value="Red" onclick="changeColor('red');" />
</form>

While this example does show how $get can be used, it really isn't too useful since most ASP.NET web applications use server controls.  One thing we all have learned is that the ID assigned to the server control in the markup is not necessarily the same ID that is generated when the control is rendered.  No worries though, this can be overcome by using the ClientID property of the server control as the next sample demonstrates.

Sample Usage 2

For the second sample, we will update our sample page to use the Button and Label server controls instead of regular HTML elements.  Additionally, I am going to move the Label and Button controls into a ContentPage to further show why using the ClientID is required for the sample to work.  After adding the Buttons and Label to the page, I update the changeColor function to grab the ClientID value from the label like so ...

<asp:Content runat="server" ContentPlaceHolderID="ContentPlaceHolder1">
    <asp:ScriptManager runat="server" />
    <script type="text/javascript">
        
        function changeColor(color){
            //  fetch the div
            var div = $get('<%= this.label.ClientID %>');
            
            //  set the color to the provided value
            div.style.color = color;
        }    
        
    </script>
    <asp:Label 
        ID="label" runat="server" 
        Text=
        "Some sample text.  You can change the color of the text by clicking the buttons" />
    <br />
    <asp:Button 
        id="btnBlue" runat="server" 
        Text="Blue" OnClientClick="changeColor('blue');return false;" />
    <asp:Button 
        id="btnGreen" runat="server" 
        Text="Green" OnClientClick="changeColor('green');return false;" />
    <asp:Button 
        id="btnRed" runat="server" 
        Text="Red" OnClientClick="changeColor('red');return false;" />
</asp:Content>  

Now if we view source for this page, you will notice that because the server controls are contained within a content page, the ID value I assigned the Label and Buttons has been prefixed with 'ctl00_ContentPlaceHolder1_'.  Below is what was actually sent to the browser.  Notice how all of the ID's are different from what we defined in the markup, but our JavaScript function still works since it was using the ClientID (the value was generated and output during the rendering process) ... 

<script type="text/javascript">
    
    function changeColor(color){
        //  fetch the div
        var div = $get('ctl00_ContentPlaceHolder1_label');
        
        //  set the color to the provided value
        div.style.color = color;
    }    
    
</script>
<span id="ctl00_ContentPlaceHolder1_label">
Some sample text.  You can change the color of the text by clicking the buttons
</span>
<br />
<input 
    type="submit" name="ctl00$ContentPlaceHolder1$btnBlue" 
    value="Blue" onclick="changeColor('blue');return false;" 
    id="ctl00_ContentPlaceHolder1_btnBlue" />
<input 
    type="submit" name="ctl00$ContentPlaceHolder1$btnGreen" 
    value="Green" onclick="changeColor('green');return false;" 
    id="ctl00_ContentPlaceHolder1_btnGreen" />
<input 
    type="submit" name="ctl00$ContentPlaceHolder1$btnRed" 
    value="Red" onclick="changeColor('red');return false;" 
    id="ctl00_ContentPlaceHolder1_btnRed" />

 

If I would have tried to fetch the Label using the ID I assigned the control in the markup, it would not have found it and the page would not work properly.  While this example is a little bit more 'real world' than the original one, it really only works when you have access to the naming container the control (the Label in this case) you want to fetch resides in.  What if we wanted to change the text color of a row in a GridView based on the user clicking one of these three buttons?  Now that might actually be interesting ...

Sample Usage 3

So this brings us to our third sample usage.  In this example, I created a GridView with 2 columns.  Once for the text that we want to change the color of and the other containing the buttons.  To support this scenario I handle the GridView's RowDataBound event and set the OnClientClick property of the Buttons to invoke my changeColor JavaScript function, passing it the ClientID of the label (this ID will be different for every row) and the color that we want the text changed to.  Here is the screen shot of this grid and below that is the sample markup and code.  Notice that when I set the OnClientClick, I am using the ClientID property of the Label.

 

<asp:Content runat="server" ContentPlaceHolderID="ContentPlaceHolder1">
    <asp:ScriptManager runat="server" />
    <asp:ObjectDataSource 
        ID="odsCustomers" runat="server" 
        SelectMethod="Select" TypeName="CustomersDataObject" />
    <script type="text/javascript">
        
        function changeColor(labelID, color){
            //  fetch the div
            var div = $get(labelID);
            
            //  set the color to the provided value
            div.style.color = color;
        }    
        
    </script>
    <script runat="server">
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        protected void GvText_RowDataBound(object sender, GridViewRowEventArgs args)
        {
            if (args.Row.RowType == DataControlRowType.DataRow)
            {
                //  get the controls from the row
                Button btnBlue = (Button)args.Row.FindControl("btnBlue");
                Button btnGreen = (Button)args.Row.FindControl("btnGreen");
                Button btnRed = (Button)args.Row.FindControl("btnRed");
                Label lblText = (Label)args.Row.FindControl("lblText");

                const string onClientClick = "changeColor('{0}', '{1}'); return false;";

                //  set the OnClientClick to call our JavaScript function
                btnBlue.OnClientClick = 
                    string.Format(onClientClick, lblText.ClientID, "blue");
                btnGreen.OnClientClick = 
                    string.Format(onClientClick, lblText.ClientID, "green");
                btnRed.OnClientClick = 
                    string.Format(onClientClick, lblText.ClientID, "red");
            }
        }
    </script>
    
    <asp:GridView 
        ID="gvText" runat="server" PageSize="5" AllowPaging="true" 
        DataSourceID="odsCustomers" AutoGenerateColumns="false"
        OnRowDataBound="GvText_RowDataBound">
        <Columns>
            <asp:TemplateField HeaderText="Text">
                <ItemTemplate>
                    <asp:Label 
                        ID="lblText" runat="server" 
                        Text=
                        "Some sample text.  You can change the ..." />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Colors">
                <ItemTemplate>
                    <asp:Button id="btnBlue" runat="server" Text="Blue" />
                    <asp:Button id="btnGreen" runat="server" Text="Green" />
                    <asp:Button id="btnRed" runat="server" Text="Red" />
                </ItemTemplate>
            </asp:TemplateField>            
        </Columns>
    </asp:GridView>
</asp:Content> 

Thats it for the $get function, but before I move on to $find, I just wanted to point out a few items that I believe are minor documentation bugs with the asp.net/AJAX site related to the $get function ...

The documentation for $get reads ...

Provides a shortcut to the getElementById method, which returns an array of all components that have been registered with the application by using the addComponent method.

Is this second part correct?  Shouldn't this actually read ... Provides a shortcut to the getElementById method, which gets a DOM element that has the specified id attribute.

Also, the code sample for $get doesn't actually include using $get in the sample code. 

$find

Overview

The $find shortcut function allows you to look up an ASP.NET AJAX client side Component by it's ID.  Here is a link to the $find shortcut's documentation and below is the API description.

Use $find to Fetch an AjaxControlToolkit Extender Behavior

Many of the extender controls of the AjaxControlToolkit include a client side JavaScript API that allows your page to interact with the extender control from the client.  While the documentation on the toolkit is well above average, it focuses on the most common properties/attributes of the control and skims over the other less used properties/attributes as well as the client side API.  I have found the best way to learn about the client side API is to download the toolkit and browse the code. 

Once you discover the capabilities of an extender's the client side API, you are going to need to obtain a reference to the component so you can interact with it from your page.  All of the extender controls in the toolkit expose a property called BehaviorID (it is defined on the ExtenderControlBase so all toolkit controls inherit it by default).  You can set the BehaviorID in the controls markup, or you can leave it blank, in which case it will have the same ID of the control.  The 2 code samples below show both of these options.  In the first one, no BehaviorID is specified so this attribute takes on the same value as the ID.  In the second sample, I am explicitly specifying a BehaviorID of 'rceBehaviorID', so that is what I can use to look up the Component.

<%--
    The behavior for this extender can be fetched using the following syntax:
    var behavior = $find('rce1ID');
--%>
<ajaxToolkit:ResizableControlExtender ID="rce1ID" runat="server" ... />

<%--
    The behavior for this extender can be fetched using the following syntax:
    var behavior = $find('rceBehaviorID');
--%>            
<ajaxToolkit:ResizableControlExtender ID="rce2ID" BehaviorID="rceBehaviorID" runat="server" ... />

Here is the JavaScript the ASP.NET AJAX runtime injects into the page to initialize these components.  Notice the value of the id attribute in the JSON:

<script type="text/javascript">
<!--
Sys.Application.initialize();
Sys.Application.add_init(function() {
    $create(
        AjaxControlToolkit.ResizableControlBehavior, 
        {
            "ClientStateFieldID":"rce1ID_ClientState",
            "HandleCssClass":"handleImage",
            "id":"rce1ID"
        }, 
        null, null, $get("pnl"));
});
Sys.Application.add_init(function() {
    $create(
        AjaxControlToolkit.ResizableControlBehavior, 
        {
            "ClientStateFieldID":"rce2ID_ClientState",
            "HandleCssClass":"handleImage",
            "id":"rceBehaviorID"
        }, 
        null, null, $get("pnl"));
});
// -->
</script>

That's it.  Enjoy!


TrackBack

TrackBack URL for this entry:
http://mattberseth.com/blog-mt/mt-tb.fcgi/61

Listed below are links to weblogs that reference The Ever-Useful $get and $find ASP.NET AJAX Shortcut Functions:

» Beware the $(...) in jQuery: $( from CodeClimber
Beware the $(...) in jQuery: $( [Read More]

Comments


Posted by: Joseph Ghassan on August 26, 2007 12:00 AM

Hi Matt,

Thanks for these nice tutorials and hands-on examples, really usefull!

Keep them up!

regards,

Joseph

.NET Web Developer @ globalvis.com

Posted by: Asif Muhammad on August 27, 2007 12:00 AM

Thanks Matt you saved my day.

Posted by: Andrei Johann on August 29, 2007 12:00 AM

Thanks Matt !

Very useful!

congratulations !

Andrei

Posted by: pwrjng on October 25, 2007 12:00 AM

Thank you so much!!!! Your blog has been a great help for me!!! Thank you so much!

Posted by: Dimas on December 12, 2007 12:00 AM

Hi thanks for the article. How would you use $get in a separate JS file? all your examples work only because the javascript function is embeded in the page, which is not really recommended. The other thing is that you can only assign ClientID in codebehind if you want to hook server control with the javascript function. I wished something like this would work asp:button OnclientClick= doSomething(label.ClientID) runat="server" (blog restricted me to write the code).

@Dimas

A simple way to achieve this would be to change the JS function to include the DIV ID like :

And in the CodeBehind :

You get the idea...

HTH

Posted by: Ed on January 30, 2008 12:00 AM

I used this to fix a validator that wasnt working correctly. Thank you.

Posted by: Edi on February 18, 2008 12:00 AM

Uff... thank you soooo much for this post. After all the rubbish ive googled this realy saved my day. Thanks *bighug*!

Posted by: Mitesh on March 20, 2008 12:00 AM

Hey Matt!!

the blog was og great help, I am new to Ajax.

this info helped me a lot

Posted by: Dmitriy on April 4, 2008 12:00 AM

Hello, Matt
How can I find an elements on the page with help $get/$find functions if I want to use an nesting key?
For example:
$find/$get("span.error_picker span")
In this case the function returns null. I used to work with jQuery and I am a little confused now

Posted by: Satish on April 23, 2008 12:00 AM

Hi Matt,

Thanks a lot. the article was very useful.

Good job!

Just what I needed, nice work

Posted by: ls82 on July 30, 2008 03:44 PM

Very Helpful

Posted by: Starfarm on October 9, 2008 10:38 AM

Hi Matt

Thanks for the tutorial. I just have one quiestion, I don't know if you have time to answer it, or else maybe somebody else in here can.

I want to use the $find() on a modalpopup, which is inside a repeater. I tried to use the thing with the parent $(ModalPopupExtender1, Parent) but it doesn't seem to work... Anybody has the answer?

Thanks again, Matt.

Posted by: BradC on October 16, 2008 12:25 PM

Matt,

thanks so much for this blog.
I was using a RegisterClientScriptBlock with the javascript document.getElementById('mycontrol') and it was not working, was getting "object does not support that method or property"
As soon as I switched to using $get, it worked the first time.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Consulting Services

Yep - I also offer consulting services. And heck, I'll do just about anything. If you enjoy my blog just drop me an email describing the work you need done.

Recent Comments

  • BradC wrote: Matt, thanks so much for this blog. I was using a RegisterClientScriptBlock with the javascript doc...
  • Starfarm wrote: Hi Matt Thanks for the tutorial. I just have one quiestion, I don't know if you have time to answe...
  • ls82 wrote: Very Helpful...
  • darkevil wrote: Just what I needed, nice work ...
  • theme wrote: Good job! ...
  • Satish wrote: Hi Matt, Thanks a lot. the article was very useful. ...
  • Dmitriy wrote: Hello, Matt How can I find an elements on the page with help $get/$find functions if I want to use a...
  • Mitesh wrote: Hey Matt!! the blog was og great help, I am new to Ajax. this info helped me a lot ...