Friday, June 5, 2009

Difference between $get and $find

In my previous blogs I have made use of $get and $find javascript methods. These are new shortcut methods available in ASP.NET AJAX. To use these methods one has include ScriptManager in an aspx page. What are these two methods all about? Lets see one by one.

$get

$get is the shortcut method for document.getElementById. If you put a break point in the $get function and step into the function you can see the following code.

var $get = Sys.UI.DomElement.getElementById = function Sys$UI$DomElement$getElementById(id, element) { 
    var e = Function._validateParams(arguments, [
        {name: "id", type: String},
        {name: "element", mayBeNull: true, domElement: true, optional: true}
    ]);
    if (e) throw e;
    if (!element) return document.getElementById(id);
    if (element.getElementById) return element.getElementById(id);
    var nodeQueue = [];
    var childNodes = element.childNodes;
    for (var i = 0; i < childNodes.length; i++) {
        var node = childNodes[i];
        if (node.nodeType == 1) {
            nodeQueue[nodeQueue.length] = node;
        }
    }
    while (nodeQueue.length) {
        node = nodeQueue.shift();
        if (node.id == id) {
            return node;
        }
        childNodes = node.childNodes;
        for (i = 0; i < childNodes.length; i++) {
            node = childNodes[i];
            if (node.nodeType == 1) {
                nodeQueue[nodeQueue.length] = node;
            }
        }
    }
    return null;
}

From the above code one can infer that the signature of the shortcut method is something like this.

$get(id, element)

The function argument “id” takes a string value where one can pass the id of the element to be retrieved. “element” is an optional parameter, if passed the code will try to find a control inside the element if it supports getElementById else it will loop through all the child nodes and match the id of the child node with the id passed as the function argument. Below sample code shows the usage of the $get.

//Getting the ASP.NET server control' id using the ClientID.
var txtCntl = $get('<% =txtChange.ClientID%>');
//Getting a control which is not a server control
var divCntl = $get('contentDiv');
//Passing the id of the control as well the control in which the controls needs to be searched.
var dropDownCntl = $get('<% =ddCountries.ClientID %>', divCntl);

--Html tag for the above controls is pasted below--
<form id="form1" runat="server">
    <div id="contentDiv">
        <asp:DropDownList ID="ddCountries" runat="server">
        </asp:DropDownList>
        <asp:TextBox ID="txtChange" runat="server"></asp:TextBox>
        <asp:Button ID="Button1" runat="server" Text="Button" />       
    </div>
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
</form>

In the above code we have seen the different ways of retrieving a control using the $get function. If you see the javascript code pasted above one can see in the first line we are trying to retrieve a ASP.NET server control using inline server code where we are using ClientID property to retrieve the system generated ID for the server control. In the second line we are using the id of the Div tag to retrieve the div control. Finally in the third line we are making use of ClientID and then passing the div control retrieved in the second line as the second argument to $get function. What happens in the third approach is that the $get function tries to find the control inside the div tag. So that’ about the $get function.

$find

$find is the shortcut method for “Sys.Application.findComponent(id, parent)”. The function takes id as a string parameter and also the control in which the component needs to be searched. The second parameter is optional. If provided it will look for the component in the component or element passed as an argument. The signature of the method is as follows.

$find(id, parent)

The method looks for components registered with the addComponent javascript method. If you put a debug point and step into the function you can see the below code.

function Sys$_Application$findComponent(id, parent) {
    var e = Function._validateParams(arguments, [
        {name: "id", type: String},
        {name: "parent", mayBeNull: true, optional: true}
    ]);
    if (e) throw e;
    // Need to reference the application singleton directly beause the $find alias
    // points to the instance function without context. The 'this' pointer won't work here.
    return (parent ?
        ((Sys.IContainer.isInstanceOfType(parent)) ?
            parent.findComponent(id) :
            parent[id] || null) :
        Sys.Application._components[id] || null);
}

From the above code you can see that the code first checks whether the parent element is of type IContainer if it is then it tries to find the component within the parent component else it returns the component from the _components array in the Sys.Application object.

When to use $get and $find?

$get javascript shortcut method can be used instead of document.getElementById whereas $find can be used to find extender controls. If you use $get to retrieve extender controls like ValidatorCalloutExtender, AutoCompleteExtender etc it will return null.

So that's the difference between $get and $find.

28 comments:

  1. whoa. glad ive found this blog. your info really helped me alot. tnx!

    ReplyDelete
  2. The post was really helpful and very explanatory. But I didnt get the exact difference between $get and $find. Can you please provide some more information about it with example.

    Thanks

    ReplyDelete
  3. When you want to retrieve normal ASP.NET controls like textbox, checkbox, button etc you can use $get. Controls which are extender controls cannot be retrieved through $get. Extender controls like ValidatorCalloutExtender, AutoCompleteExtender etc can be retrieved using $find. Hope this clears your doubt.

    ReplyDelete
  4. Yes, I am clear. Thanks a lot for the useful and important information.
    BTW I am Prajakta, I have gone thro' your profile. Nice one.

    ReplyDelete
  5. Hi Prajakta,
    I am happy that you are clear on the difference between $get and $find. Thanks.

    ReplyDelete
  6. Nice Post Sandeep ..

    ReplyDelete
  7. Sandeep,

    I am using $find to get the header for a particular tab on an AJAX TabContainer, as follows (tabContainer and tabindex are vars):

    var tabHeader = $find(tabContainer).get_tabs()[tabindex]._header;

    In this case what would the parent be? The tabContainer is on an ASPX page.

    Thanks, and great post!

    ReplyDelete
  8. Hi Dave,
    Sorry for the late reply. I was not in town, went to attend Microsoft Tech-Ed.

    The parent of the header should be the individual tab in the tab container control. The _header property will return a span object. If you try to get parent object using the "parentElement" property you won't get the tab. Instead you will get another span. The best way is to use the "get_tabs()" method to get the individual tab if that is what you want. Hope this is what you were looking forward for.

    ReplyDelete
  9. Hi Sandeep,

    I had gone through your explansion, its very helpful. i had one doubt, if we use $get for an extender control, it returns null. but i use $find
    for an non-extender control, what is the result, will it gets the control or returns null.

    ReplyDelete
  10. If I am not wrong you are asking what will happen if I use "$find to access textbox, button and other html controls, then the answer is that you will get "null".

    ReplyDelete
  11. Nice Post Sandeep, recentyl I faced this question in interview. Thanx for the information.

    ReplyDelete
  12. Hi Amol,
    I am happy to hear that the post was helpful in your interview. Hope you did good?

    ReplyDelete
  13. Hi! Congratulations for the nice post!
    Maybe you can help me... Are there limitations about calling $find in a javascript that have been registered through a ScriptManager.RegisterClientScriptBlock? I'm getting a "object required" error in that case, but i can use it without any problems otherwise.

    Ty and keep the good work!

    ReplyDelete
  14. Hi,
    I think the reason for object required is that the DOM is not completed build. RegisterClientScriptBlock is registered at the top of the aspx page before the body tag and at this point the DOM is not constructed. This could be the reason why you are getting "object required" error.

    ReplyDelete
  15. Sandeep can you take a look please?

    Using MasterPages and ModalPopupExtender works fine but need client-side validation for certain steps of a WizardControl located in a Content Page.

    $find [can't|won't] find the ModalPopUpExtender in its Content Page. When Button Control is selected alert() always returns the null message.

    // Button Control...


    // Script.js
    function itemBuilderModalPopup() {
    var modalPopup = $find('<%= ItemBuilderFinishButtonModalPopup.ClientID %>');
    if (modalPopup == null) {
    alert("ModalPopUp == null");
    }
    if (modalPopup != null) {
    alert("ModalPopUp != null");
    }
    }

    // ModalPopUpExtender in Viewed Source
    Sys.Application.add_init(function() {
    $create(AjaxControlToolkit.ModalPopupBehavior, {"BackgroundCssClass":"modalBackground","CancelControlID":"CenterPanelContent_ItemBuilderWizard_StepNavigationTemplateContainerID_CancelPopUpButton","PopupControlID":"CenterPanelContent_ItemBuilderWizard_StepNavigationTemplateContainerID_ImageBuilderOptionsModalPopUp","dynamicServicePath":"/METROfeed/Rss/ItemBuilder/ItemBuilder.aspx","id":"CenterPanelContent_ItemBuilderWizard_StepNavigationTemplateContainerID_ItemBuilderFinishButtonModalPopup"}, null, null, $get("CenterPanelContent_ItemBuilderWizard_StepNavigationTemplateContainerID_FinishButton"));
    });

    "Working with Modal Popup extender control" was one of the best blog items I've learned from. Thank you for any insight you can provide...

    ReplyDelete
  16. Sir i n using ajax html extender & i want to tell u that $get also works for that too

    ReplyDelete
  17. Thanks for sharing such a great information with us. Your Post is very unique and all information is reliable for new readers. Keep it up in future, thanks for sharing such a useful post.
    Here Is Daily Latest Updated Mobile Price for Bangladeshi People Who are looking for all mobile price to buy smartphone. I hope you guys will be like this Mobilepriceall Website. Thanks again.

    ReplyDelete
  18. Your article is just amazing.You might be interested in:mathppa

    ReplyDelete
  19. I Love your article. You can visit my website : block strike free play

    ReplyDelete

Please provide your valuable comments.