admin管理员组

文章数量:1297083

I'm desperate having spent well over an hour trying to troubleshoot this. I am trying to access a node in the DOM which is created from an ASP.NET control. I'm using exactly the same id and I can see that they match up when looking at the HTML source code after the page has rendered. Here's my [MODIFIED according to suggestions, but still not working] code:

ASP.NET Header

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script type="text/javascript">
    $(document).ready(
        var el = document.getElementById('<%= txtBox.ClientID %>');
        el.onchange = alert('test!!');
    )
    </script>
</asp:Content>

ASP.NET Body

<asp:TextBox ID="txtBox" runat="server"></asp:TextBox>

Resulting Javascript & HTML from above

<script type="text/javascript">
$(document).ready(
    var el = document.getElementById('MainContent_txtBox');
    el.onchange = alert('test!!');
)
</script>
...
<textarea name="ctl00$MainContent$txtBox" id="MainContent_txtBox"></textarea>

I can only assume that the script is loading before the control id has been resolved, yet when I look at the timeline with Chrome's "Inspect Element" feature, it appears that is not the case. When I created a regular textarea box to test and implement the identical code (different id of course), the alert box fires.

What on earth am I missing here? This is driving me crazy >.<

EDIT: Wierd code that works, but only on the initial page load; firing onload rather than onchange. Even jQuery says that .ready doesn't work properly apparently. Ugh!!

$(document).ready(function() {
    document.getElementById('<%= txtBox.ClientID %>').onchange = alert('WORKING!');
})

I'm desperate having spent well over an hour trying to troubleshoot this. I am trying to access a node in the DOM which is created from an ASP.NET control. I'm using exactly the same id and I can see that they match up when looking at the HTML source code after the page has rendered. Here's my [MODIFIED according to suggestions, but still not working] code:

ASP.NET Header

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script type="text/javascript">
    $(document).ready(
        var el = document.getElementById('<%= txtBox.ClientID %>');
        el.onchange = alert('test!!');
    )
    </script>
</asp:Content>

ASP.NET Body

<asp:TextBox ID="txtBox" runat="server"></asp:TextBox>

Resulting Javascript & HTML from above

<script type="text/javascript">
$(document).ready(
    var el = document.getElementById('MainContent_txtBox');
    el.onchange = alert('test!!');
)
</script>
...
<textarea name="ctl00$MainContent$txtBox" id="MainContent_txtBox"></textarea>

I can only assume that the script is loading before the control id has been resolved, yet when I look at the timeline with Chrome's "Inspect Element" feature, it appears that is not the case. When I created a regular textarea box to test and implement the identical code (different id of course), the alert box fires.

What on earth am I missing here? This is driving me crazy >.<

EDIT: Wierd code that works, but only on the initial page load; firing onload rather than onchange. Even jQuery says that .ready doesn't work properly apparently. Ugh!!

$(document).ready(function() {
    document.getElementById('<%= txtBox.ClientID %>').onchange = alert('WORKING!');
})
Share Improve this question edited Jul 22, 2011 at 2:11 Chiramisu asked Jul 22, 2011 at 0:08 ChiramisuChiramisu 4,7267 gold badges51 silver badges78 bronze badges 2
  • 2 Aside from the document-ready issues, the syntax of your onclick is incorrect. You need to assign onclick to point to a function, not call it as if it was a function. So try changing it to something like el.onclick = function() { alert("test"); };, or you can do el.onclick = myFunction; (note no brackets after the name of your function) where elsewhere on the page you've defined function myFunction() { ... }. – nnnnnn Commented Jul 22, 2011 at 1:02
  • Ack!! I'm tired for today. I'll pick this up again tomorrow and determine an answer then. Thanks guys ;) – Chiramisu Commented Jul 22, 2011 at 1:37
Add a ment  | 

3 Answers 3

Reset to default 5

Assuming the rendered markup does appear in that order, the problem is that the element doesn't yet exist at the time your JavaScript is attempting to locate it.

Either move that JS below the element (preferably right at the end of the body) or wrap it in something like jQuery's document ready event handler.

Update:

In response to your edits, you're almost there but (as others have mentioned) you need to assign a function to the onchange event, not the return result of alert(). Something like this:

$(document).ready(function() {
  // Might as well use jQuery to attach the event since you're already using
  //  it for the document ready event.
  $('#<%= txtBox.ClientID %>').change(function() {
    alert('Working!');
  });
});

By writing onchange = alert('Working');, you were asking JavaScript to assign the result of the alert() method to the onchange property. That's why it was executing it immediately on page load, but never actually in response to the onchange event (because you hadn't assigned that a function to run onchange).

Pick up jQuery.

Then you can

$(function()
{
    var el = document.getElementById('<%= txtBox.ClientID %>');
    el.onclick() { alert('test!!'); }
});

Other answers have pointed out the error (attempting to access DOM nodes before they are in the document), I'll just point out alternative solutions.

Simple method

Add the script element in the HTML below the closing tag of the element you wish to access. In its easiest form, put it just before the closing body tag. This strategy can also make the page appear faster as the browser doesn't pause loading HTML for script. Overall load time is the same however, scripts still have to be loaded an executed, it's just that this order makes it seem faseter to the user.

Use window.onload or <body onload="..." ...>

This method is supported by every browser, but it fires after all content is loaded so the page may appear inactive for a short time (or perhaps a long time if loading is dealyed). It is very robust though.

Use a DOM ready function

Others have suggested jQuery, but you may not want 4,000 lines and 90kb of code just for a DOM ready function. jQuery's is quite convoluted so hard to remove from the library. David Mark's MyLibrary however is very modular and quite easy to extract just the bits you want. The code quality is also excellent, at least the equal of any other library.

Here is an example of a DOM ready function extracted from MyLibrary:

var API = API || {};

(function(global) {

  var doc = (typeof global.document == 'object')? global.document : null;

  var attachDocumentReadyListener, bReady, documentReady,
      documentReadyListener, readyListeners = [];
  var canAddDocumentReadyListener, canAddWindowLoadListener,
      canAttachWindowLoadListener;

  if (doc) {
    canAddDocumentReadyListener = !!doc.addEventListener;
    canAddWindowLoadListener    = !!global.addEventListener;
    canAttachWindowLoadListener = !!global.attachEvent;

      bReady = false;
      documentReady = function() { return bReady; };
      documentReadyListener = function(e) {
        if (!bReady) {
          bReady = true;
          var i = readyListeners.length;
          var m = i - 1;
          // NOTE: e may be undefined (not always called by event handler)
          while (i--) { readyListeners[m - i](e); }
        }
      };

      attachDocumentReadyListener = function(fn, docNode) {
        docNode = docNode || global.document;
        if (docNode == global.document) {
          if (!readyListeners.length) {
            if (canAddDocumentReadyListener) {
              docNode.addEventListener('DOMContentLoaded',
                                        documentReadyListener, false);
            }
            if (canAddWindowLoadListener) {
              global.addEventListener('load', documentReadyListener, false);
            }
            else if (canAttachWindowLoadListener) {
              global.attachEvent('onload', documentReadyListener);
            } else {
              var oldOnLoad = global.onload;              
              global.onload = function(e) { 
                  if (oldOnLoad) { 
                    oldOnLoad(e); 
                  }
                  documentReadyListener();
              };
            }
          }
          readyListeners[readyListeners.length] = fn;
          return true;
        }
        // NOTE: no special handling for other documents
        // It might be useful to add additional queues for frames/objects
        else {
          if (canAddDocumentReadyListener) {
            docNode.addEventListener('DOMContentLoaded', fn, false);
            return true;
          }
          return false;
        }
      };

      API.documentReady = documentReady;
      API.documentReadyListener = documentReadyListener;
      API.attachDocumentReadyListener = attachDocumentReadyListener;

  }
}(this));

Using it for your case:

function someFn() {
  var el = document.getElementById('MainContent_txtBox');
  el.onclick = function() { alert('test!!');
}

API.attachDocumentReadyListener(someFn);

or an anonymous function can be supplied:

API.attachDocumentReadyListener(function(){
  var el = document.getElementById('MainContent_txtBox');
  el.onclick = function() { alert('test!!');
};

Very simple DOM ready functions can be done in 10 lines of code if you just want one for a specific case, but of course they are less robust and not as reusable.

本文标签: javascriptGetElementById of ASPNET Control keeps returning 39null39Stack Overflow