difference between setAttribute and htmlElement.attribute='value' - javascript

what would be the difference between the two ,
b1.setAttribute('id','b1');
and
b1.id='b1';
is one of them more efficient than the other ? and do both of them will do exactly the same task ? and will they be different in some situations ?

difference between setAttribute and htmlElement.attribute='value'
That latter bit, htmlElement.attribute='value', isn't quite accurate. You're not setting an attribute there, you're setting a property.
DOM element instances in memory have various properties, some of which connect to or relate to attributes and others which don't.
Attributes, on the other hand, are name/value pairs that are read directy from the HTML markup (and if you serialize a DOM element, for instance by accessing its innerHTML property, are written to the markup you get back).
When the property and attribute are related/linked in some way, the property is called a reflected property (of the attribute). Sometimes, the reflected property's name isn't quite the same as the attribute's name (class becomes className, for becomes htmlFor), and sometimes the link between them isn't 1:1.
So for instance, id is a reflected property of the id attribute. But select boxes have a selectedIndex property for which there's no attribute.
do both of them will do exactly the same task ?
and will they be different in some situations ?
It depends on the attribute/property:
id and several others are directly reflected: Setting the id property and setting the id attribute do exactly the same thing. Offhand, this is also true of the htmlFor property / for attribute (except on old IE which has bugs in setAttribute there), the rel property/attribute, the className / class attribute (except on old IE which has bugs in setAttribute there), the name attribute on form fields and some other elements, the method and action properties/attributes on forms, and several others.
The value property, on the other hand, doesn't set the value attribute at all. It just gets its default value from it. On most browsers ("all" at this point?), there's a separate defaultValue property which does directly reflect the value attribute.
The href property is slightly different from the href attribute in relation to relative vs. absolute links. The attribute can contain a relative path, and using str = elm.getAttribute("href") gives you that relative path; if you read the property (str = elm.href), it will always be an absolute path (e.g., the resolved path). Setting the href property to a relative path sets the attribute to that path, but again reading teh href property will give you the absolute (resolved) version. Setting the href property to an absolute path will set the attribute to that absolute path.
There are several boolean properties which are represented as booleans (true/false), but since attribute values are always strings, the attribute is either not there for false (getAttribute returns null) or there for true. If it's there, it must have the value "" or the same as its name (e.g., multiple="multiple", case-insensitive), although in practice browsers treat any present attribute as true regardless of its actual content.
Several properties aren't reflected in attributes at all, so setting them doesn't set/change any attribute.
is one of them more efficient than the other ?
It's never going to make a big enough difference to care, so it doesn't matter. It also probably varies dramatically by browser.

Related

Where in the specification is it defined that HTML attributes can be referenced from JavaScript?

I always referenced element attribute values in the form element.value,element.id. I recently learned about the getAttribute function. I can see the definition of the getAttribute function, but I couldn't find a section that defined that attribute values can be referenced from JavaScript like element.id.
I thought it was defined by the WHATWG, so I read DOM LS Chapter 4 and HTML LS 3.2.4.1 and the whole Chapter 3. However, their definitions were not found. Is this a feature that is not specified in the specification and depends on the browser implementation?
They are defined in the HTML specification. For example, see the input element which includes a section titled "DOM interface" which says, among other things:
[CEReactions] attribute [TreatNullAs=EmptyString] DOMString value;
and links to the definition of the value property.
Note, however, that the value property does not map to the value attribute but to the current value.
It's described in the DOM Living Standard under 4.9. Interface Element here:
Among other things, it specifies:
element . id [ = value ]
Returns the value of element’s id content attribute. Can be set to change it.
element . className [ = value ]
Returns the value of element’s class content attribute. Can be set to change it.
element . classList
Allows for manipulation of element’s class content attribute as a set of whitespace-separated tokens through a DOMTokenList object.
element . slot [ = value ]
Returns the value of element’s slot content attribute. Can be set to change it.

Assign an object to an element as an attribute in java script

I have this scenario where i need to assign a java-script object to div attribute.
var temp["name"]="first";
i assigned it to a div tag attribute using Jquery.
div.attr('data-polygon',temp);
Object [ <div#image01> ]
when i try to retrieve it , it does not come back same.. it is converted as String.
div.attr('data-polygon');
"[object Object]"
Any proper option / alternate to retain the object in attribute? please let me know
Attributes are always strings.
Here are two options for doing this; since you're already using jQuery, the first is probably best:
jQuery's data
jQuery provides the data method for doing this:
// Setting -- notice no "data-" prefix
div.data("polygon", temp);
// Retrieving
varName = div.data("polygon");
Under the covers, traditionally data assigns the element a unique ID and manages a data cache for the element, separate from it. I think in the v3 branch they've updated it to actually store the data on the element (there were memory issues with doing that in Internet Explorer 8 and earlier, which is why jQuery didn't do it before).
Assign it as your own "expando" property
If you don't need to support Internet Explorer 8, you can just create a property on the actual DOM element.
// Setting
rawDiv.myUniquePrefixToAvoidConflicts_polygon = temp;
// Getting
varName = rawDiv.myUniquePrefixToAvoidConflicts_polygon;
Note that to avoid conflicts with the many predefined properties elements have, and future ones they don't have yet, you'll want to use a likely-unique prefix.

jQuery get/select element by property value

Is there a way to get/select an element by it's property value, just as it is possible with the attribute values:
$('[attribute="value"]')
For example, I'd set a property using jQuery like this:
$('#foo').prop('my-property', 'value');
and then I'd like to find an element which has property 'my-property' and it has value 'value'.
No, there isn't anything exposed at the selector level that can select by property value, just (as you know) attribute value.
Some properties are reflections of attributes, which means that setting the property sets the attribute, which allows you to use attribute selectors. For instance, an input element's defaultValue property is a reflection of its value attribute (which its value property is not).
Otherwise, you select by what you can and use filter to filter the resulting list to only the elements you actually want.
Re your edit:
For example, I'd set a property using jQuery like this:
$('#foo').prop('my-property', 'value');
No, there's no way to select by that property directly, you'd need something like my filter suggestion above:
var list = $("something-that-gets-you-close").filter(function() {
return this["my-property"] == "value";
});
You might consider using data-* attributes instead:
$("#foo").attr("data-my-property", "value");
then
var list = $("[data-my-property='value']");
to select it (the inner quotes are optional for values matching the definition of a CSS identifier). Note that attribute values are always strings.
Beware: There's a persistent misconception that jQuery's data function is a simple accessor for data-* attributes. It is not. It manages a data cache associated with the element by jQuery, which is initialized from data-* attributes but disconnected from them. In particular, .data("my-property", "value") would not let you find that later via a [data-my-property=value] selector.

why name attribute couldn't set using javascript?

I wish to change the name attribute at dynamic in JavaScript, but I couldn't change the name attribute using either element.name or the setAttribute() method. Is there any other way to set the name attribute?
var status_Element = document.getElementsByName("BD_task_status_"+old_id+"[]");
var final_status_Element = document.getElementsByName("BD_final_task_status_"+old_id+"[]");
for(var in_count=0;in_count<status_Element.length;in_count++)
{
status_Element[in_count].name="BD_task_status_level"+inner_count+"[]";
final_status_Element[in_count].name="BD_final_task_status_level"+inner_count+"[]";
}
Setting the name property as in your example will work (other than the inner_count vs in_count typo). The issue is that getElementsByName returns a live collection of elements. When you change the name of the element at index 0, it no longer belongs in the collection and the collection drops it; then the element that used to be at index 1 is now at index 0. But in the meantime, you've incremented in_count and so you never end up changing that element. Half of them will end up not being changed.
Either:
Loop backward through the collection to change the names (since then the element that disappears is at the end and you don't care), or
Use querySelectorAll instead, which gives you a snapshot collection (not a live one). (querySelectorAll is supported on all modern browsers, and also IE8.)

Best method to get attributes from getElementsByTagName()?

I'm playing around with getting attributes of a link tag, there seems to be several ways of accessing the attributes:
document.getElementsByTagName("link")[0]['media']
document.getElementsByTagName("link")[0].media
document.getElementsByTagName("link")[0].getAttribute('media')
document.getElementsByTagName("link")[0].attributes['media']
It's bordering on ridiculous how many paths there are to the same data. Is one of these methods far superior to the rest?
I would use .media for this case, since media is indeed a property on the link element. Each of these has its use:
['media']: Retrieves the "media" property value using square bracket notation. Use square bracket notation when you don't know the name of the property at design time. For example, when iterating properties.
.media: Retrieves the "media" property value. I'd use this in most cases. It provides concise, direct access to the property value.
.getAttribute('media'): Retrieves the "media" attribute value. Use this when you want the value of an attribute that is not necessarily a property on the element. Not all attributes are properties and not all properties are attributes.
.attributes['media']: Retrieves the "media" attribute node. Use the attributes collection when you need more information about an attribute than just it's value. For example, the attribute name. You can also easily use this to get the value, since .toString() returns the value, but that may be overkill if all you want is the value. The attributes collection is also useful for iterating the attributes of an element.
The method you are looking for is called getElementsByTagName. It returns an array-like list of elements (which is not an array).
Note that your last sample .attributes['media'] does not return a string as the other methods. It returns an attribute node instead.
In theory the ways of accessing the content should be equivalent but browser bugs led to other behavior in reality. It's probably best to use an abstraction layer (a library such as jQuery) to get consistent behavior. If you intend to program without a library the choice depends on your taste however I'd say that going via the attribute node is safest in general.
To add a bit more technical detail, although the different way return the same ways most of the time this is not necessarily true for non-existent attributes. Take the following HTML as example: <a href='test'>. You can try it yourself in another browser on a test jsFiddle (the output below is from Firefox).
// Get reference to element
var a = document.getElementsByTagName('a')[0];
// Existent attributes
console.log(a.href); // String: http://fiddle.jshell.net/_display/test
console.log(a.getAttribute('href')); // String: test
console.log(a.attributes['href']); // Attribute node: href
Note that one time an absolute URI was returned, another time the original value was returned.
// Existent invalid attributes
console.log(a.other); // undefined
console.log(a.getAttribute('other')); // String: thing
console.log(a.attributes['other']); // Attribute node: other
Everything that exists on page load gets merged into DOM but is not available as property if invalid.
// Inexistent but valid attributes
console.log(a.title); // Empty string
console.log(a.getAttribute('title')); // null
console.log(a.attributes['title']); // undefined
The first call returned a properties default value. Then we saw null as a marker for an inexistent attribute. Lastly we got a so called NamedNodeMap which is something like a mixture of an array and object. Accessing it as an object gave the undefined value.
// Creating attributes
a.setAttribute('title', 'test title');
console.log(a.title); // String: test title
console.log(a.getAttribute('title')); // String: test title
console.log(a.attributes['title']); // Attribute node: title
Attribute becomes available as property, too.
// Creating "attributes" by using property
a.rel = 'test rel';
console.log(a.rel); // String: test rel
console.log(a.getAttribute('rel')); // String: test rel
console.log(a.attributes['rel']); // Attribute node: rel
Setting property for a valid attribute also creates an entry in attributes map.
// Inexistent invalid attributes
console.log(a.dummyInvention); // undefined
console.log(a.getAttribute('dummyInvention')); // null
console.log(a.attributes['dummyInvention']); // undefined
Property access on a, marker return value and index access on node map.
// Creating invalid attributes via setAttribute
a.setAttribute('title2', 'test title2');
console.log(a.title2); // undefined
console.log(a.getAttribute('title2')); // String: test title2
console.log(a.attributes['title2']); // Attribute node: title2
Attribute gets created even though its existent is invalid but it is not available as property.
// Creating invalid "attributes" via property
a.title3 = 'test title3';
console.log(a.title3); // String: test title3
console.log(a.getAttribute('title3')); // null
console.log(a.attributes['title3']); // undefined
Object a is extended but DOM is untouched.
// NamedNodeMap of length 4 and indexes other, href, title, rel, title2 (valid attributes or result of setAttribute in order of creation except those from parsing)
console.log(a.attributes);
The node map only reflects the current state of the DOM. It is not aware of extension to our object a that we received via getElementsByTagName.
It's important to note that manipulating JavaScript object does not necessarily affect the DOM. The DOM only reflects the things that have been available on parsing plus modification with DOM methods or property modifications (of predefined properties that is). I hope I did not miss any important cases and that the comments have been verbose enough to see what happens.
I would appreciate a comment on the final NamedNodeMap because I would like to know if Firefox's behavior is correct there to discard the order of the attributes from parsing.
Functionally, they are equal.
Performance-wise, the first two are superior by a significant factor - though they are all extremely fast. See this JSPerf test.
Practically speaking, the first two are easier to read, and my personal preference is the second. (It's also a hair faster.)
The first two options are the the same. You can use either. I personally prefer the .media version since I think it reads easier.
The last two options depend upon getAttribute() and setAttribute() which have not always been reliable in IE. You can read a lot more about that in the reference that Matt posted. As such, I prefer the .media version out of all four of your choices as most reliable and most readable.

Categories

Resources