Functionality of Javascript functions and jquery selectors from within html - javascript

I have this javascript function:
function clearDiv(div_id) {
alert(div_id);
$(div_id).empty();
}
And the following html:
<input value="Clear" type="button" onClick="clearDiv(div_to_clear)" />
<div id="div_to_clear">
<!-- more html -->
</div>
Why is it that the above will actually find the javascript div object with id div_to_clear and use the $ selector to access it?
If I had done the input as :
<input value="Clear" type="button" onClick="clearDiv('div_to_clear')" />
I would need to change my function to
function clearDiv(div_id) {
alert(div_id);
$('#' + div_id).empty();
}
Is there any documentation about this? Are there advantages to using one method or the other?

IE (and Chrome in an effort for compatability) will create properties on the window with names of elements with ids, corresponding to those elements.
In the first example are are passing window.div_to_clear which points to your element directly. In the second, you are passing a string telling jQuery which element to select.
The first one is non-standard behavior so you should not rely on it.

The first one is actually a browser bug (they called it a feature) to access the DOM node by window.div_to_clear (the global variable) - and jQuery creates its wrapper around the element. For legacy reasons, it still exists in current browsers, but is deprecated. Your really should use the selector solution.

This is because there is a widely-implemented (although not best practice) method by browsers to automatically place html elements with id's into their correlating variable name. For example:
<div id="someId"></div>
will end up psuedo creating the variable someId which holds that html element.
These questions have similar information on the behavior:
Do DOM tree elements with ids become global variables?
Where does the variable holding an element with an id get stored?
Element accessible with ID
Here is a jsperformance test showing that accessing the id in that manner is slower than using document.getElementById: http://jsperf.com/global-id-vs-document-getelementbyid

Related

javascript .value wont get anything [duplicate]

How can I get a collection of elements by specifying their id attribute? I want to get the name of all the tags which have the same id in the html.
I want to use ONLY getElementById() to get an array of elements. How can I do this?
I know this is an old question and that an HTML page with multiple identical IDs is invalid. However, I ran into this issues while needing to scrape and reformat someone else's API's HTML documentation that contained duplicate IDs (invalid HTML).
So for anyone else, here is the code I used to work around the issue using querySelectorAll:
var elms = document.querySelectorAll("[id='duplicateID']");
for(var i = 0; i < elms.length; i++)
elms[i].style.display='none'; // <-- whatever you need to do here.
The HTML spec requires the id attribute to be unique in a page:
[T]he id attribute value must be unique amongst all the IDs in the element's tree
If you have several elements with the same ID, your HTML is not valid.
So, document.getElementById should only ever return one element. You can't make it return multiple elements.
There are a couple of related functions that will return a list of elements: getElementsByName or getElementsByClassName that may be more suited to your requirements.
Why you would want to do this is beyond me, since id is supposed to be unique in a document. However, browsers tend to be quite lax on this, so if you really must use getElementById for this purpose, you can do it like this:
function whywouldyoudothis() {
var n = document.getElementById("non-unique-id");
var a = [];
var i;
while(n) {
a.push(n);
n.id = "a-different-id";
n = document.getElementById("non-unique-id");
}
for(i = 0;i < a.length; ++i) {
a[i].id = "non-unique-id";
}
return a;
}
However, this is silly, and I wouldn't trust this to work on all browsers forever. Although the HTML DOM spec defines id as readwrite, a validating browser will complain if faced with more than one element with the same id.
EDIT: Given a valid document, the same effect could be achieved thus:
function getElementsById(id) {
return [document.getElementById(id)];
}
document.querySelectorAll("#yourId"); returns all elements whose id is yourId
It is illegal to have multiple elements with the same id. The id is used as an individual identifier. For groups of elements, use class, and getElementsByClassName instead.
The id is supposed to be unique, use the attribute "name" and "getelementsbyname" instead, and you'll have your array.
As others have stated, you shouldn't have the same ID more than once in your HTML, however... elements with an ID are attached to the document object and to window on Internet Explorer. Refer to:
Do DOM tree elements with ids become global variables?
If more than one element with the same ID exists in your HTML, this property is attached as an array. I'm sorry, but I don't know where to look if this is the standard behavior or at least you get the same behavior between browsers, which I doubt.
Class is more than enough for refering anything you want, because it can have a naming with one of more words:
<input class="special use">
<input class="normal use">
<input class="no use">
<input class="special treatment">
<input class="normal treatment">
<input class="no special treatment">
<input class="use treatment">
that's the way you can apply different styles with css (and Bootstrap is the best example of it) and of course you may call
document.getElementsByClassName("special");
document.getElementsByClassName("use");
document.getElementsByClassName("treatment");
document.getElementsByClassName("no");
document.getElementsByClassName("normal");
and so on for any grouping you need.
Now, in the very last case you really want to group elements by id. You may use and refer to elements using a numerically similar, but not equal id:
<input id=1>
<input id="+1">
<input id="-1">
<input id="1 ">
<input id=" 1">
<input id="0x1">
<input id="1.">
<input id="1.0">
<input id="01.0">
<input id="001">
That way you can, knowing the numeric id, access and get an element by just adding extra non-invalidating numeric characters and calling a function to get (by parsing and so on) the original index from its legal string identifying value. It is useful for when you:
Have several rows with similar elements and want to handle its events
coherently. No matter if you delete one or almost all of them.
Since numeric reference is still present, you can then reuse them and
reassign its deleted format.
Run out of class, name and tagname identifiers.
Although you can use spaces and other common signs even when it's a not a requirement strictly validated in browsers, it's not recommended to use them, specially if you are going to send that data in other formats like JSON. You may even handle such things with PHP, but this is a bad practice tending to filthy programming practices.
This is my solution:
<script type="text/javascript">
$(document).ready(function () {
document.getElementsByName("mail")[0].value = "ex_mail1";
document.getElementsByName("mail")[1].value = "ex_mail2";
});
</script>
Or you can use for-loop for that.
You shouldn't do that and even if it's possible it's not reliable and prone to cause issues.
Reason being that an ID is unique on the page. i.e. you cannot have more than 1 element on the page with the same ID.
you can use
document.document.querySelectorAll("#divId")
we can use document.forms[0].Controlid
If you're using d3 for handling multiple objects with the same class / id
You can remove a subset of class elements by using d3.selectAll(".classname");
For example the donut graph here on http://medcorp.co.nz utilizes copies of an arc object with class name "arc" and there's a single line of d3, d3.selectAll(".arc").remove(); to remove all those objects;
using document.getElementById("arc").remove(); only removes a single element and would have to be called multiple times (as is with the suggestions above he creates a loop to remove the objects n times)

Access to object property or method from appended element jquery

I would like to know if it's possible to access an object property from an appended element. For example:
function anyFct(){
this.div=$('<div ref="dv">').html('Hi').appendTo('body');
div.animal='dog';
div.yld=function(){
alert(div.animal);
};
$('input type="text" value="anyIn" onclick="yeldAnimal(this);"').appendTo(div);
}
function yeldAnimal(obj){
var actElement=$(obj).closest('div[ref=dv]');
actElement.yld(); // I want that this yields 'dog'
}
and my HTML:
<input type="button" value="test" onclick="anyFct();">
So this is the logic: I create a div element when the button is clicked on. This div element has a text that when clicked on calls an external function that calls a method on its parent element (the div).
For many contextual reasons this must be the logic. I've already found a solution that is saving the object div in a global array and then search in all values of the array for the object that triggered the method. However, I would like to know if there is a 'cleaner' or correct way to do this.
It's possible, and there are a couple of ways you could achieve it. The important thing you need to understand is the distinction between jQuery objects and actual DOM elements. When you use jQuery to create a <div> element, you create both; but what you end up with a reference to is the jQuery object - or, if you're chaining jQuery function calls, the result of the last function called. The DOM element, assuming you actually append it to the DOM, persists once that section of code has finished execution, but the jQuery object that's created will vanish when that variable goes out of scope.
When you execute some jQuery code later on to get a reference to your DOM element, it's referring to the same element on your page but it's a different jQuery object, so any custom properties you added to the original one won't be available. How do you get around that? Set the properties on the actual DOM element.
You can use the .get() method to access the underlying DOM element from a jQuery object, indexed from 0 (so .get(0) called on a jQuery object will return the first DOM element it references). With that you can then set your custom properties and later retrieve them, something like this:
function anyFct(){
this.div=$('<div ref="dv">').html('Hi').appendTo('body');
var elem = div.get(0); // the actual DOM element, the div
elem.animal='dog';
elem.yld=function(){
alert(elem.animal);
};
$('<input type="text" value="anyIn" onclick="yeldAnimal(this);"/>').appendTo(div);
}
function yeldAnimal(obj){
var actElement=$(obj).closest('div[ref=dv]').get(0); // also the div
actElement.yld(); // alerts 'dog'
}
jsFiddle demo
Note that I've made a few changes to your code in addition to adding in the usage of .get(), most notably correcting the syntax for creating the <input type="text"> element in the first function.
Okay, most of this is not syntactically correct javascript and seems to be overly complicated. I believe if I understand what you're trying to achieve you want the following:
function anyFct(){
var div=$('<div ref="dv">').html('Hi');
div.animal='dog';
div.yld=function(){
alert(this.animal);
};
var element = $('<input type="text" value="anyIn">');
$(element).click(function() {
div.yld();
});
$(div).append(element);
$('body').append(div);
}

set variable value as attribute using JS

This is my code:
var chk="checked";
document.getElementById("chk").chk=true;
where I used variable to set attribute in the second line.
but this is not working with no error.
Please help me to find this.
You might want:
document.getElementById("chk").setAttribute(chk, true);
which will set it as HTML attribute (not the object property - for that you'd use [] brackets). This is what you're probably looking for because you're operating on an HTMLElememnt.
To clarify:
setAttribute - set's an attribute on an HTML element. It will turn this: <div> into that: <div checked="true"> (assuming the element under question is a div)
[] - use for plain JS objects. In that case the name 'property' is rather used, not 'attribute'
Also note that if the element is <input>, both approaches will work. That's because HTMLInputElement contains the 'checked' attribute. See HTMLInputElement MDN page for details.
Use like this.
document.getElementById("chk").setAttribute(chk, true);
Try this:
document.getElementById("chk")[chk] = true;
This one sets the property
or use the .setAttribute property
document.getElementById("chk").setAttribute(chk, true);
This will set the attribute. If you are using it on HTML elements then this one is a better pick for you as this will set the HTML attribute.
Try,
document.getElementById("chk")[chk] = true;
You can add variables to any JavaScript object which is why the code will run without an error, but -- as you've observed -- it won't have any side effects if the property is not a predefined, semantically meaningful one. For that, you should read some documentation for the given element. For the checkbox element, the name of the property you are looking for is checked. (Note that using the dot syntax treats the text to the right as the name of the property, it does not evaluate it, first. For dynamic evaluation of the property name, use the [] syntax for normal objects and setAttribute for HTML attributes).
chk is a javascript variable in your case. When you getElementById, it refers to the HTML document and the tags in it. Example,
<input id=appleId type="radio" name="fruit" value="Apple" />
In JS, you can then say,
document.getElementById("appleId").checked = true;
Refer to How can I check whether a radio button is selected with JavaScript?

Javascript focus() and select() quirk

Im working on a form and getting null or not an object errors in ie.
<form action="#" method="post" name="adv_search">
<input class="inputbox" type="text" name="keyword1" value="none" id="keyword1"/>
</form>
<script>
document.adv_search.keyword1.focus();
document.adv_search.keyword1.select();
</script>
//whereas if I use
<script>
var key1 = document.getElementById('keyword1');
key1.focus();
key1.select();
</script>
//everything is fine
i would like to understand why.
i would like it to work without having the id tag for the input field
thanks in advance
shouldnt the document.formname.fieldname.focus();
and document.formname.fieldname.select();
work?
Your particular example works for me, but if I add another field with the same name:
<input type="text" name="keyword1" />
<input type="text" name="keyword1" />
Then document.adv_search.keyword1.focus() will fail with the error you specify.
The reason is that:
document.adv_search.keyword1
is a shortcut for this syntax (which goes back to DOM Level 0 and the Netscape 2 days!):
document.forms.adv_search.elements.keyword1
(Incidentally, it is better to use this full syntax, instead of relying on the behaviour of the ‘document’ and ‘form’ objects being indexed on names: if a new method is added to HTMLDocument or HTMLFormElement, that might clash with the control name you are using. This is less of an issue when you use the document.forms or form.elements collections. Also, IE mistakenly dumps all names and ids into ‘document’, so if you've got an element with id="adv_search" in addition to the form with that as a name, document.adv_search will return the wrong one.)
Anyway, the DOM Level 0 scripting methods behave slightly curiously when you access an element by name like this. If there is a single matching element, you'll get that one as a standalone object. If, on the other hand, there are more than one, you'll get a list of objects. You can't call focus() or select() on an array-like list, which is why the error appears; you'd have to do something like keyword1[0].focus() when the list was returned.
So you have to decide whether you're going to be using old-school DOM Level 0 methods to access your form controls — in which case you're going to have to cope with sniffing for single-or-multiple-controls — or move to the ID-based methods introduced by ‘DOM Level 1’:
document.getElementById('keyword1').focus();
The ID-based methods are generally a bit more typing (in the script and to add ‘id’s to all elements you wish to access this way, if they don't already have them), but they are simple and unambiguous. (Also you can then drop the name on the <form> itself.)
The ID approach really is best but if you want to go by name, use getElementsByName.
In this case, it might look like this:
<script>
// retrieves array of objects with the name 'keyword1'
// and takes the first one
var key1 = document.getElementsByName('keyword1')[0];
key1.focus();
key1.select();
</script>

How to Maintain Correct Javascript Event After Using cloneNode(true)

I have a form element that contains multiple lines of inputs. Think of each line as attributes of a new object that I want to create in my web application. And, I want to be able to create multiple new objects in one HTTP POST. I'm using Javascript's built-in cloneNode(true) method to clone each line. The problem is that each input-line also has a removal link attached to its onclick-event:
// prototype based
<div class="input-line">
<input .../>
Remove
</div>
When the cloned input-line's removal link is clicked, it also removes any input-lines that were cloned from the same dom object. Is it possible to rebind the "this" object to the proper anchor tag after using cloneNode(true) on the above DOM element?
Don't put handler on each link (this really should be a button, BTW). Use event bubbling to handle all buttons with one handler:
formObject.onclick = function(e)
{
e=e||event; // IE sucks
var target = e.target||e.srcElement; // and sucks again
// target is the element that has been clicked
if (target && target.className=='remove')
{
target.parentNode.parentNode.removeChild(target.parentNode);
return false; // stop event from bubbling elsewhere
}
}
+
<div>
<input…>
<button type=button class=remove>Remove without JS handler!</button>
</div>
You could try cloning using the innerHTML method, or a mix:
var newItem = $(item).cloneNode(false);
newItem.innerHTML = $(item).innerHTML;
Also: I think cloneNode doesn't clone events, registered with addEventListener. But IE's attachEvent events are cloned. But I might be wrong.
I tested this in IE7 and FF3 and it worked as expected - there must be something else going on.
Here's my test script:
<div id="x">
<div class="input-line" id="y">
<input type="text">
Remove
</div>
</div>
<script>
$('x').appendChild($('y').cloneNode(true));
$('x').appendChild($('y').cloneNode(true));
$('x').appendChild($('y').cloneNode(true));
</script>
To debug this problem, I would wrap your code
$(this).up().remove()
in a function:
function _debugRemoveInputLine(this) {
debugger;
$(this).up().remove();
}
This will allow you to find out what $(this) is returning. If it is indeed returning more than one object (multiple rows), then you definitely know where to look -- in the code which creates the element using cloneNode. Do you do any modification of the resulting element (i.e. changing the id attribute)?
If I had the problem you're describing, I would consider adding unique IDs to the triggering element and the "line" element.
First answer is the correct one.
Pornel is implicitly suggesting the most cross-browser and framework agnostic solution.
Haven't tested it, but the concept will work in these dynamic situations involving events.
Looks like you're using jQuery? It has a method to clone an element with events: http://docs.jquery.com/Manipulation/clone#true
EDIT: Oops I see you're using Prototype.

Categories

Resources