Scope of inline JavaScript vs script element [duplicate] - javascript

It is common for me to register javascript functions for certain events by doing something like:
myBtn.Attributes.Add("onClick", "Validate(getElementById('"+txtFirstName.ClientID + "'));");
I've always used getElementById by itself, or in other words, sans document being prepended to it. But I'm having pages break on me lately when I try to use getElementById instead of document.getElementById. Why is this? Oddly, I have a website where one page allows me to use just getElementById, but another other page throws a javascript error because it can't find the element if I do just getElementById, and it'll only work if I do document.getElementById.
Anyone know why this is? Should I be using document.getElementById everywhere, regardless of whether it works without the document prefix?
EDIT:
Could it have anything to do with the fact that one page is using AJAX and the other isn't?

When you use getElementById() and it works that mean that the function where it's called is running on the context of the document, that's is this == document.
So, you should ALWAYS use document.getElementById to avoid that kind of errors.
Anyway, I would even stop using getElementById altogether and start using JQuery, i'm sure you'll never regret it.
Your code would look something like this if you used JQuery:
$("#myBtnID").click(function () { Validate($("#myTextboxID"))});

Any function or variable you access without an owning object (ex: document.getElementById) will access the property from window.
So getElementById is actually window.getElementById, which isn't natively defined (unless you defined it before (ex: getElementById = document.getElementById).

You should use the full document.getElementById(). If you find that too verbose, you could use jQuery:
$('#' + id)
or you could create an alias at the top of your script:
var byID = document.getElementById;

You should only use document.getElementById (even if I'd recommend using libraries like prototype or jquery to be able to use the $ sign).
If you are able to use getElementById on its own, it's just because the browser you're using is doing some kind of trick to get it to work, but the correct way is to use the document variable.

I dont really know how to explain it but its because the getElementById() finds an element in the html structure of a page. Some browsers know that by default you want to search the document, but other browsers need that extra guidance hence document.

The correct way is indeed document.getElementById().
The reason (speculation) it might work by itself is that depending on where you use it the current context may in fact be the document object, thus inexplicitly resulting in document.getElementById().

Related

Can't get access elements with querySelector?

I wish to access elements in a site with javascript and I have been using javascript for quite some time, especially with the querySelector functions. But for some reason, it won't work in this case; whenever I try to access any of the top-level elements, as illustrated below, no elements are found.
Does anyone have an idea about what the problem could be, and maybe even how to fix it?
That's normal,
It's because when you use the chrome developer console you can change the document context and in your screen you are inside the iframe.
You can see it here:

document.formname.checkbox[0].checked versus document.getElementById('checkbox').checked

In Javascript, I usually use the syntaxdocument.formname.checkbox[0].checked, but I notice that almost everyone else uses document.getElementById('checkboxid').checked. My apologies if this seems a silly question, but I'm trying to find out if my preferred syntax has been deprecated, or do others simply use what is more convenient?
What each means:
document.formname.checkbox[0].checked
This uses the form's and the element's name= attribute to select the element you want. It's good because sometimes you don't want to dirty your markup with IDs everywhere, and you'd prefer to use names, which are something most forms has (because default submission uses names as keys).
The potential problems with that is that it's a bit verbose, and might not very readable.
document.getElementById('checkboxId').checked
This has the simplicity of just plugging an ID and getting the correct element, but then to get any element in the form, it must also have an ID, which can be pretty annoying.
document.querySelectorAll('#myForm input[type=checkbox]')[0].checked
Here's an alternative solution, which uses CSS selectors and document.querySelectorAll(), I feel that it's more readable, especially for people who are more proficient in CSS than in JavaScript.
Which of those is better? Depends on your particular use case and preference. I like to use querySelector and querySelectorAll, especially if I already have the form DOM object in a variable:
myForm.querySelector('input[type=checkbox]').checked;
It's up to you.
getElementById is preferred. Consider a webpage with the following contents:
<div id="x"></div>
You can access your div x in javascript with just console.log(x).
Now consider if you had var x = 5 defined in the global context. Well, now you can't use x to access your div before it now has a value of just 5.
getElementById is preferred because you don't have the potential to overwrite your selector with a variable for something else.
document.formname.checkbox[0].checked might not actually work on all Browsers. document.forms[0].elements and document.formName is standardized, as is document.getElementById()

How is this element accessible when not found with selector

In my company, some of the code accesses html elements purely by id, rather than document.getElementById or jQuery $("#id"). For example, if there is a select with an id of test they then use alert(test.selectedIndex) in the javascript and this works.
This breaks my model of how elements can be found / accessed in the DOM and I would have expected the alert to say that test was undefined. However, this works (and I have set up a fiddle to double check this). Can anyone please explain why elements can be accessed by their id, without any need for a getElementById / jQuery selector?
Many thanks.
See http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object (noting that 'globals' in javascript are just looked up from properties on the window object, so window[id] is exactly the same as just id, if id is not defined as a local variable)
This was previously non-standard behaviour, added by IE, that has now become part of the HTML5 spec.
In general I wouldn't recommend relying on it though because, as you've noticed, it can be quite confusing.

Is using document.getElementsByTagName() a good idea or bad idea?

Ok so I am wondering which way is the preffered way to access a certain tag.
Is it better to use..
document.getElementById('myDiv').innerHTML
or this way..
document.getElementsByTagName('div')[0].innerHTML
// I use [0] because it is the first div in the body
My guess is that it doesn't matter at all which way i do it.
Absolutely the getElementById is better in that case. It's much faster.
Update
Here is a test about JavaScript selector functions. http://jsperf.com/queryselectorall-vs-getelementbyid/6
There are not many articles about performance of JavaScript selector functions. Instead there are many articles about jQuery selector performance like this or this. jQuery uses native JavaScript selector functions internally, so you can guess from these articles.
They do completely different things. If you want to get a particular element and you always need to get the same element, use an id. If you want to get a particular element based on what place it has in the DOM, then use the it's position in the getElementsByTagName NodeList.
If you want to get a particular element and you get it by index, then your script will be brittle - if you change your DOM structure later, you will need to change your code. If you want to get an element by it's position, then using an ID will require you to add redundant attributes to your markup.
Also, it is important to note that getElementById returns a DOM node, while getElementsByTagName returns a NodeList. To quote MDC on the properties of a NodeList:
NodeList is live, meaning that it updates itself automatically to stay in sync with the DOM tree without having to call document.getElementsByTagName again.
So if you need a particular element, getElementById will be significantly faster.
For readability purposes, it depends on what you're trying to do.
Is your intent to get the first div, which just happens to be named myDiv? if yes, then I think getElementsByTagName is better, as it would more express what you're trying to do.
Or is your intent to get myDiv, which just happens to be the first div? If that's the case, then use getElementById.
All other considerations aside, go with the one that expresses your intent.

Using selenium's waitForCondition with an xpath

Selenium has some nice support for finding elements in a page via xpath
selenium.isElementPresent("//textarea")
and in ajax pages you can use waitForCondition to wait on a page until something appears
selenium.waitForCondition("some_javascript_boolean_test_as_a_string", "5000")
My difficulty is, I can't seem to get into a position to use the xpath support for the boolean test. document.getElementById seems to work fine, but selenium.isElementPresent doesn't.
Is there any easy way of accessing selenium's xpath element finding abilities from within waitForCondition's first parameter?
An more straightforward way to do it is:
selenium.waitForCondition("selenium.isElementPresent(\"xpath=//*[#id='element_id_here']/ul\");", time_out_here);
You could do something like this:
selenium.waitForCondition(
"var x = selenium.browserbot.findElementOrNull('elementIdOrXPathExpression');"
+ "x != null && x.style.display == 'none';", "5000");
The waitForCondition just evaluates the last js expression result as a boolean, thereby allowing you to write complex tests (as shown here). For example, we're also using this technique to test whether jQuery AJAX has finished executing.
The only drawback is you're also now relying on the browserbot and the lower level core js API.
If you want to select an element by id, the simplest thing is to use straight selenese:
isElementPresent("textarea")
If you insist on using xpath you may have to use
isElementPresent("//*[#id='textarea']")
or
isElementPresent("//id('textarea')")
(The id function may not be cross-browser compatible)
If this does not help your html document may also have structural issues that is causing this to happen. Run an html validator like html validator to check for nesting problems and similar on your page.

Categories

Resources