jquery removeAttr('id') vz. removeProp('id') [duplicate] - javascript

This question already has answers here:
What is the difference between removeProp and removeAttr in JQuery 1.6?
(3 answers)
Closed 7 years ago.
can somebody explains me how to remove id from element in right way?
I thought that jQ prop() is new prefered form of attr() and removeProp() as well.
But if i try to remove id by removeProp('id') jQ sets the id of element to id='undefined'. It produces the elements with id='undefined'(as I see in debuger) and I don't think it is corect. ID should be unique on the page. Shouldn't it?
RemoveAttr() removes the id from the element as I expect(it means element have not id as I see in debuger). But I am not sure what is the corect way to do it?
Can you explain it?
Thanks!

I think the confusion comes from before jQuery 1.6, in which the .attr() function sometimes would take property values into account before retrieving attributes. This was inconsistent behavior. As of jQuery 1.6 .prop() explicitly retrieves property values and .attr() explicitly attributes.
What is odd, still, is that .prop() accepts elements' disabled attribute as valid. The disabled feat of elements is seen as an attribute not a property.
Among this, yes, you should be using .removeAttr() to remove the id attribute. Not .removeProp()

The difference between attr and prop is easy: the first one gets or sets content attributes (a.k.a attributes), and the second one gets or sets IDL attributes (a.k.a properties).
When there are an attribute and a property with the same name, prop is usually preferred because it shows the current state of the element.
For example, the value property of an input element is its current value. Its value attribute is its the initial value (that's the same as the defaultValue property).
Note this is not the case of id, because the property reflects the attribute, so they always are the same.
When you want to delete, it's different. You can remove attributes freely, but properties are non-deletable. That's because those properties are implemented as inherited getters/setters, but only own properties can be deleted.
var el = document.createElement('div');
el.id = 'foo';
el.hasOwnProperty('id'); // false
delete el.id; // Does not delete
el.id; // "foo"
In jQuery 1, deleteProp was implemented like
removeProp: function( name ) {
name = jQuery.propFix[ name ] || name;
return this.each(function() {
// try/catch handles cases where IE balks (such as removing a property on window)
try {
this[ name ] = undefined;
delete this[ name ];
} catch( e ) {}
});
}
Therefore, the id became "undefined" because of this[ name ] = undefined;.
In jQuery 2 they changed that to
removeProp: function( name ) {
return this.each(function() {
delete this[ jQuery.propFix[ name ] || name ];
});
}
Therefore, now deleteProp('id') does not alter the id.
So if you want to remove the id, better remove the attribute.

Related

How to disable a button click in JavaScript? [duplicate]

I’ve read that you can disable (make physically unclickable) an HTML button simply by appending disable to its tag, but not as an attribute, as follows:
<input type="button" name=myButton value="disable" disabled>
Since this setting is not an attribute, how can I add this in dynamically via JavaScript to disable a button that was previously enabled?
Since this setting is not an attribute
It is an attribute.
Some attributes are defined as boolean, which means you can specify their value and leave everything else out. i.e. Instead of disabled="disabled", you include only the bold part. In HTML 4, you should include only the bold part as the full version is marked as a feature with limited support (although that is less true now then when the spec was written).
As of HTML 5, the rules have changed and now you include only the name and not the value. This makes no practical difference because the name and the value are the same.
The DOM property is also called disabled and is a boolean that takes true or false.
foo.disabled = true;
In theory you can also foo.setAttribute('disabled', 'disabled'); and foo.removeAttribute("disabled"), but I wouldn't trust this with older versions of Internet Explorer (which are notoriously buggy when it comes to setAttribute).
to disable
document.getElementById("btnPlaceOrder").disabled = true;
to enable
document.getElementById("btnPlaceOrder").disabled = false;
It is an attribute, but a boolean one (so it doesn't need a name, just a value -- I know, it's weird). You can set the property equivalent in Javascript:
document.getElementsByName("myButton")[0].disabled = true;
Try the following:
document.getElementById("id").setAttribute("disabled", "disabled");
The official way to set the disabled attribute on an HTMLInputElement is this:
var input = document.querySelector('[name="myButton"]');
// Without querySelector API
// var input = document.getElementsByName('myButton').item(0);
// disable
input.setAttribute('disabled', true);
// enable
input.removeAttribute('disabled');
While #kaushar's answer is sufficient for enabling and disabling an HTMLInputElement, and is probably preferable for cross-browser compatibility due to IE's historically buggy setAttribute, it only works because Element properties shadow Element attributes. If a property is set, then the DOM uses the value of the property by default rather than the value of the equivalent attribute.
There is a very important difference between properties and attributes. An example of a true HTMLInputElement property is input.value, and below demonstrates how shadowing works:
var input = document.querySelector('#test');
// the attribute works as expected
console.log('old attribute:', input.getAttribute('value'));
// the property is equal to the attribute when the property is not explicitly set
console.log('old property:', input.value);
// change the input's value property
input.value = "My New Value";
// the attribute remains there because it still exists in the DOM markup
console.log('new attribute:', input.getAttribute('value'));
// but the property is equal to the set value due to the shadowing effect
console.log('new property:', input.value);
<input id="test" type="text" value="Hello World" />
That is what it means to say that properties shadow attributes. This concept also applies to inherited properties on the prototype chain:
function Parent() {
this.property = 'ParentInstance';
}
Parent.prototype.property = 'ParentPrototype';
// ES5 inheritance
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
function Child() {
// ES5 super()
Parent.call(this);
this.property = 'ChildInstance';
}
Child.prototype.property = 'ChildPrototype';
logChain('new Parent()');
log('-------------------------------');
logChain('Object.create(Parent.prototype)');
log('-----------');
logChain('new Child()');
log('------------------------------');
logChain('Object.create(Child.prototype)');
// below is for demonstration purposes
// don't ever actually use document.write(), eval(), or access __proto__
function log(value) {
document.write(`<pre>${value}</pre>`);
}
function logChain(code) {
log(code);
var object = eval(code);
do {
log(`${object.constructor.name} ${object instanceof object.constructor ? 'instance' : 'prototype'} property: ${JSON.stringify(object.property)}`);
object = object.__proto__;
} while (object !== null);
}
I hope this clarifies any confusion about the difference between properties and attributes.
It's still an attribute. Setting it to:
<input type="button" name=myButton value="disable" disabled="disabled">
... is valid.
If you have the button object, called b: b.disabled=false;
I think the best way could be:
$("#ctl00_ContentPlaceHolder1_btnPlaceOrder").attr('disabled', true);
It works fine cross-browser.
<button disabled=true>text here</button>
You can still use an attribute. Just use the 'disabled' attribute instead of 'value'.

create variables for all elements using id attributes

need to create variables from all elements having id attribute
name of each variable should be just the value of id attribute
for example <div id='btnsave'>SAVE</div> - should be a variable named btnsave
here is my try - without success:
let els = $("*");
els.forEach(function(el){
if(el.hasId()){
console.log(el.attr('id'));
window[el] = $('#' + el);
}
});
If you're using id attributes for your elements then they already have references accessible through the properties of the window object which match their id value:
console.log(window.foo.textContent);
console.log(window.fizz.textContent);
<p id="foo">bar</p>
<p id="fizz">buzz</p>
Given your comment under the question:
I have a lot of divs as buttons and is simpler to write btnsave.on('click'... then $('#btnsave').on('click'...
In that case you simply need to cache the selector at the top of your script (within scope) and use it where required. This is a standard pattern to follow.
Creating jQuery objects from every element in the DOM with an id and storing them in the window object is an anti-pattern, which will cause performance issues and most likely break native code which expects those references to contain DOMElement objects, not jQuery objects.
Do not do it.
To get elements by any attribute you can use query selector.
let elementsWithId = {}
document.querySelectorAll('[id]').forEach(el => {
elementsWithId[el.id] = el
})
console.log(elementsWithId)
You can record a jQuery element to window variable. Example:
window[el.id] = $(el)
But as people mentioned, this is a bad practice.

Find elements by id, class and attr combined in jquery

I have the following code:
$("#modal-bool-element").change(function(e) {boolSettings($(e.target))});
function boolSettings(e) {
elem = e;
var boolSettingsParent = elem.closest("#bool-settings");
if (elem.is(":checked") == true) {
elem.val(true);
boolSettingsParent.find("#modal-bool-show").prop("disabled", false);
} else {
elem.val(false);
boolSettingsParent.find(".bool-reset, .bool-offset").hide();
boolSettingsParent.find("#modal-bool-show").val("never");
boolSettingsParent.find("#modal-bool-show").prop("disabled", true);
boolSettingsParent.find("#modal-bool-offsetValue, #modal-bool-reset, #modal-bool-offsetUnit").val("");
}
}
What I would like to do is to pass the value of an atrribute to find method along with the classname or id. That attr is elem.attr("model-id").
I have tried like this:
boolSettingsParent.find(`#modal-bool-show [model-id='{elem.attr(model-id)}']`)
But I am not getting any value. How can I achieve the desired result?
Remove the space:
boolSettingsParent.find(`#modal-bool-show[model-id='{elem.attr(model-id)}']`)
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^
The space means you're looking for a descendant element of #modal-bool-show with that attribute. Without the space, it means you only want #modal-bool-show if it also has that attribute value.
You mentioned a class but haven't shown picking one. To do that, you'd tack on a class selector:
boolSettingsParent.find(`#modal-bool-show[model-id='{elem.attr(model-id)}'].some-class`)
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^
BUT, just the id should be sufficient unless you want to skip the element if it doesn't have that attribute and/or class, because you can't have more than one element in the DOM with the same id — doing so is invalid. So adding more things to the selector is fine if you want the selector not to match anything if the element with that id doesn't have the attribute and/or class, but if you're doing it so the selector matches the "right" element with that id, that's a problem because it means you have more than one element with the same id.
I assumed in the above that you were using some templating system that handled the {...} for you, but if you meant to use a substitution in JavaScript's template literal, they use the format ${...}, not {...}. So:
boolSettingsParent.find(`#modal-bool-show[model-id='${elem.attr(model-id)}'].some-class`)
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^

Why does element.id on element without id not return undefined or null?

Inspired by this question and dealing with a similar situation, I wonder whether anyone can explain the rationale behind the decision to have element.id return an empty string when the id attribute is not present.
If the spec was to return null or undefined I could simply write
var allIds = $('#my-frm input').map(function() { return this.id; }).get();
Instead I have to either add a qualifier to the selector, as in
var allIds = $('#my-frm input[id]').map(function() { return this.id; }).get();
or use the other solution proposed to the above-mentioned question (which has to get the id twice in case it is present)
var allIds = $('#my-frm input').map(function() { return (this.id) ? this.id : null; }).get();
or I can use the jquery attribute getter, which seems unnecessary to wrap each element into a jquery object first, but I'm mentioning it for completeness and to show that jquery went the other direction with the .attr() method.
var allIds = $('#my-frm input').map(function() { return $(this).attr('id'); }).get();
I'm curious if there is a practical reason behind the javascript element.id behavior.
Update:
I finally located the relevant spec, which defines the current behavior (it doesn't explain why it was defined this way)
https://www.w3.org/TR/2015/REC-dom-20151119/#element
interface Element : Node {
readonly attribute DOMString? namespaceURI;
readonly attribute DOMString? prefix;
readonly attribute DOMString localName;
readonly attribute DOMString tagName;
attribute DOMString id;
attribute DOMString className;
...
Either when an element is created that has an id attribute whose value is not the empty string or when an element's id attribute is set to a value other than the empty string, set the element's ID to the new value.
When an element's id attribute is removed or set to the empty string, unset the element's ID.
Some IDL attributes are defined to reflect a particular content attribute of a given name. This means that on getting, these steps must be run:
Get an attribute for the context object using content attribute's name and let value be the result.
If value is null, return the empty string.
Return value.
On setting, set an attribute for the context object using the name of the attribute and the given value.
The id attribute must reflect the "id" content attribute.
I'm curious if there is a practical reason behind the javascript
element.id behavior.
See Element.id
The Element.id property represents the element's identifier,
reflecting the id global attribute.
If the spec was to return null or undefined
3.2.5.1 The id attribute
Identifiers are opaque strings. Particular meanings should not be
derived from the value of the id attribute.
Note There are no other restrictions on what form an ID can take; in particular, IDs can consist of just digits, start with a digit,
start with an underscore, consist of just punctuation, etc.
Note An element's unique identifier can be used for a variety of purposes, most notably as a way to link to specific parts of a
document using fragment identifiers, as a way to target an element
when scripting, and as a way to style a specific element from CSS.
It's funny how the result is kind of opposite of the intent. Because I
want to avoid calling a separate method to check for the existence of
id
To substituting $.map() for .map() , Array.prototype.filter() with parameter Boolean for .get() to return id that is not empty string
var allIds = $.map($("input"), function(el) {
return el.id
}).filter(Boolean);
jsfiddle https://jsfiddle.net/gqvfuzqr/

whats a difference between storing data in variable attached to Dom element vs storing data in attribute like data? [duplicate]

Has a best-practice around using setAttribute instead of the dot (.) attribute notation been developed?
E.g.:
myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");
or
myObj.className = "nameOfClass";
myObj.id = "someID";
From Javascript: The Definitive Guide, it clarifies things. It notes that HTMLElement objects of a HTML doc define JS properties that correspond to all standard HTML attributes.
So you only need to use setAttribute for non-standard attributes.
Example:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
None of the previous answers are complete and most contain misinformation.
There are three ways of accessing the attributes of a DOM Element in JavaScript. All three work reliably in modern browsers as long as you understand how to utilize them.
1. element.attributes
Elements have a property attributes that returns a live NamedNodeMap of Attr objects. The indexes of this collection may be different among browsers. So, the order is not guaranteed. NamedNodeMap has methods for adding and removing attributes (getNamedItem and setNamedItem, respectively).
Notice that though XML is explicitly case sensitive, the DOM spec calls for string names to be normalized, so names passed to getNamedItem are effectively case insensitive.
Example Usage:
var div = document.getElementsByTagName('div')[0];
//you can look up specific attributes
var classAttr = div.attributes.getNamedItem('CLASS');
document.write('attributes.getNamedItem() Name: ' + classAttr.name + ' Value: ' + classAttr.value + '<br>');
//you can enumerate all defined attributes
for(var i = 0; i < div.attributes.length; i++) {
var attr = div.attributes[i];
document.write('attributes[] Name: ' + attr.name + ' Value: ' + attr.value + '<br>');
}
//create custom attribute
var customAttr = document.createAttribute('customTest');
customAttr.value = '567';
div.attributes.setNamedItem(customAttr);
//retreive custom attribute
customAttr = div.attributes.getNamedItem('customTest');
document.write('attributes.getNamedItem() Name: ' + customAttr.name + ' Value: ' + customAttr.value + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
2. element.getAttribute & element.setAttribute
These methods exist directly on the Element without needing to access attributes and its methods but perform the same functions.
Again, notice that string name are case insensitive.
Example Usage:
var div = document.getElementsByTagName('div')[0];
//get specific attributes
document.write('Name: class Value: ' + div.getAttribute('class') + '<br>');
document.write('Name: ID Value: ' + div.getAttribute('ID') + '<br>');
document.write('Name: DATA-TEST Value: ' + div.getAttribute('DATA-TEST') + '<br>');
document.write('Name: nonStandard Value: ' + div.getAttribute('nonStandard') + '<br>');
//create custom attribute
div.setAttribute('customTest', '567');
//retreive custom attribute
document.write('Name: customTest Value: ' + div.getAttribute('customTest') + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
3. Properties on the DOM object, such as element.id
Many attributes can be accessed using convenient properties on the DOM object. Which properties exist on a given object depends on the object's DOM node type, regardless of which attributes are specified in the HTML. The available properties are defined somewhere in the prototype chain of DOM object in question. So, the specific properties that are defined will depend on the type of Element you are accessing.
For example, className and id are defined on Element and exist on all DOM nodes that are elements, but not text or comment nodes. value is more narrowly defined. It only available on HTMLInputElement and it's descendants.
Notice that JavaScript properties are case sensitive. Although most properties will use lowercase, some are camelCase. So always check the spec to be sure.
This "chart" captures a portion of the prototype chain for these DOM objects. It's not even close to complete, but it demonstrates the overall structure.
____________Node___________
| | |
Element Text Comment
| |
HTMLElement SVGElement
| |
HTMLInputElement HTMLSpanElement
Example Usage:
var div = document.getElementsByTagName('div')[0];
//get specific attributes
document.write('Name: class Value: ' + div.className + '<br>');
document.write('Name: id Value: ' + div.id + '<br>');
document.write('Name: ID Value: ' + div.ID + '<br>'); //undefined
document.write('Name: data-test Value: ' + div.dataset.test + '<br>'); //.dataset is a special case
document.write('Name: nonStandard Value: ' + div.nonStandard + '<br>'); //undefined
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
Caveat: This is an explanation of how the HTML spec define attributes and how modern, evergreen browsers handle them. There certainly are old browsers (IE, Netscape, etc.) that didn't adhere to or even predated the spec. If you need to support old ancient (broken) browsers, you'll need more information than provided here.
You should always use the direct .attribute form (but see the quirksmode link below) if you want programmatic access in JavaScript. It should handle the different types of attributes (think "onload") correctly.
Use getAttribute/setAttribute when you wish to deal with the DOM as it is (e.g. literal text only). Different browsers confuse the two. See Quirks modes: attribute (in)compatibility.
One case I found where setAttribute is necessary is when changing ARIA attributes, since there are no corresponding properties. For example
x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');
There's no x.arialabel or anything like that, so you have to use setAttribute.
Edit: x["aria-label"] does not work. You really do need setAttribute.
x.getAttribute('aria-label')
null
x["aria-label"] = "Test"
"Test"
x.getAttribute('aria-label')
null
x.setAttribute('aria-label', 'Test2')
undefined
x["aria-label"]
"Test"
x.getAttribute('aria-label')
"Test2"
These answers aren't really addressing the large confusion with between properties and attributes. Also, depending on the Javascript prototype, sometimes you can use a an element's property to access an attributes and sometimes you can't.
First, you have to remember that an HTMLElement is a Javascript object. Like all objects, they have properties. Sure, you can create a property called nearly anything you want inside HTMLElement, but it doesn't have to do anything with the DOM (what's on the page). The dot notation (.) is for properties. Now, there some special properties that are mapped to attributes, and at the time or writing there are only 4 that are guaranteed (more on that later).
All HTMLElements include a property called attributes. HTMLElement.attributes is a live NamedNodeMap Object that relates to the elements in the DOM. "Live" means that when the node changes in the DOM, they change on the JavaScript side, and vice versa. DOM attributes, in this case, are the nodes in question. A Node has a .nodeValue property that you can change. NamedNodeMap objects have a function called setNamedItem where you can change the entire node. You can also directly access the node by the key. For example, you can say .attributes["dir"] which is the same as .attributes.getNamedItem('dir'); (Side note, NamedNodeMap is case-insensitive, so you can also pass 'DIR');
There's a similar function directly in HTMLElement where you can just call setAttribute which will automatically create a node if it doesn't exist and set the nodeValue. There are also some attributes you can access directly as properties in HTMLElement via special properties, such as dir. Here's a rough mapping of what it looks like:
HTMLElement {
attributes: {
setNamedItem: function(attr, newAttr) {
this[attr] = newAttr;
},
getNamedItem: function(attr) {
return this[attr];
},
myAttribute1: {
nodeName: 'myAttribute1',
nodeValue: 'myNodeValue1'
},
myAttribute2: {
nodeName: 'myAttribute2',
nodeValue: 'myNodeValue2'
},
}
setAttribute: function(attr, value) {
let item = this.attributes.getNamedItem(attr);
if (!item) {
item = document.createAttribute(attr);
this.attributes.setNamedItem(attr, item);
}
item.nodeValue = value;
},
getAttribute: function(attr) {
return this.attributes[attr] && this.attributes[attr].nodeValue;
},
dir: // Special map to attributes.dir.nodeValue || ''
id: // Special map to attributes.id.nodeValue || ''
className: // Special map to attributes.class.nodeValue || ''
lang: // Special map to attributes.lang.nodeValue || ''
}
So you can change the dir attributes 6 ways:
// 1. Replace the node with setNamedItem
const newAttribute = document.createAttribute('dir');
newAttribute.nodeValue = 'rtl';
element.attributes.setNamedItem(newAttribute);
// 2. Replace the node by property name;
const newAttribute2 = document.createAttribute('dir');
newAttribute2.nodeValue = 'rtl';
element.attributes['dir'] = newAttribute2;
// OR
element.attributes.dir = newAttribute2;
// 3. Access node with getNamedItem and update nodeValue
// Attribute must already exist!!!
element.attributes.getNamedItem('dir').nodeValue = 'rtl';
// 4. Access node by property update nodeValue
// Attribute must already exist!!!
element.attributes['dir'].nodeValue = 'rtl';
// OR
element.attributes.dir.nodeValue = 'rtl';
// 5. use setAttribute()
element.setAttribute('dir', 'rtl');
// 6. use the UNIQUELY SPECIAL dir property
element["dir"] = 'rtl';
element.dir = 'rtl';
You can update all properties with methods #1-5, but only dir, id, lang, and className with method #6.
Extensions of HTMLElement
HTMLElement has those 4 special properties. Some elements are extended classes of HTMLElement have even more mapped properties. For example, HTMLAnchorElement has HTMLAnchorElement.href, HTMLAnchorElement.rel, and HTMLAnchorElement.target. But, beware, if you set those properties on elements that do not have those special properties (like on a HTMLTableElement) then the attributes aren't changed and they are just, normal custom properties. To better understand, here's an example of its inheritance:
HTMLAnchorElement extends HTMLElement {
// inherits all of HTMLElement
href: // Special map to attributes.href.nodeValue || ''
target: // Special map to attributes.target.nodeValue || ''
rel: // Special map to attributes.ref.nodeValue || ''
}
Custom Properties
Now the big warning: Like all Javascript objects, you can add custom properties. But, those won't change anything on the DOM. You can do:
const newElement = document.createElement('div');
// THIS WILL NOT CHANGE THE ATTRIBUTE
newElement.display = 'block';
But that's the same as
newElement.myCustomDisplayAttribute = 'block';
This means that adding a custom property will not be linked to .attributes[attr].nodeValue.
Performance
I've built a jsperf test case to show the difference: https://jsperf.com/set-attribute-comparison. Basically, In order:
Custom properties because they don't affect the DOM and are not attributes.
Special mappings provided by the browser (dir, id, className).
If attributes already exists, element.attributes.ATTRIBUTENAME.nodeValue =
setAttribute();
If attributes already exists, element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
element.attributes.ATTRIBUTENAME = newNode
element.attributes.setNamedItem(ATTRIBUTENAME) = newNode
Conclusion (TL;DR)
Use the special property mappings from HTMLElement: element.dir, element.id, element.className, or element.lang.
If you are 100% sure the element is an extended HTMLElement with a special property, use that special mapping. (You can check with if (element instanceof HTMLAnchorElement)).
If you are 100% sure the attribute already exists, use element.attributes.ATTRIBUTENAME.nodeValue = newValue.
If not, use setAttribute().
"When to use setAttribute vs .attribute= in JavaScript?"
A general rule is to use .attribute and check if it works on the browser.
..If it works on the browser, you're good to go.
..If it doesn't, use .setAttribute(attribute, value) instead of .attribute for that attribute.
Rinse-repeat for all attributes.
Well, if you're lazy you can simply use .setAttribute. That should work fine on most browsers. (Though browsers that support .attribute can optimize it better than .setAttribute(attribute, value).)
Interesting observation from Google API script regarding this:
They do it like this:
var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";
Notice, how they use setAttribute for "src" and "nonce", but then .async = ... for "async" attribute.
I'm not 100% sure, but probably that's because "async" is only supported on browsers that support direct .attr = assignment. So, there's no sense trying to setAttribute("async") because if browser doesn't understand .async=... - it will not understand "async" attribute.
Hopefully, that's a helpful insight from my ongoing "Un-minify GAPI" research project. Correct me if I'm wrong.
This looks like one case where it is better to use setAttribute:
Dev.Opera — Efficient JavaScript
var posElem = document.getElementById('animation');
var newStyle = 'background: ' + newBack + ';' +
'color: ' + newColor + ';' +
'border: ' + newBorder + ';';
if(typeof(posElem.style.cssText) != 'undefined') {
posElem.style.cssText = newStyle;
} else {
posElem.setAttribute('style', newStyle);
}
methods for setting attributes(for example class) on an element:
1. el.className = string
2. el.setAttribute('class',string)
3. el.attributes.setNamedItem(object)
4. el.setAttributeNode(node)
I have made a simple benchmark test (here)
and it seems that setAttributeNode is about 3 times faster then using setAttribute.
so if performance is an issue - use "setAttributeNode"
This is very good discussion. I had one of those moments when I wished or lets say hoped (successfully that I might add) to reinvent the wheel be it a square one.
Any ways above is good discussion, so any one coming here looking for what is the difference between Element property and attribute. here is my penny worth and I did have to find it out hard way. I would keep it simple so no extraordinary tech jargon.
suppose we have a variable calls 'A'. what we are used to is as following.
Below will throw an error because simply it put its is kind of object that can only have one property and that is singular left hand side = singular right hand side object. Every thing else is ignored and tossed out in bin.
let A = 'f';
A.b =2;
console.log(A.b);
who has decided that it has to be singular = singular. People who make JavaScript and html standards and thats how engines work.
Lets change the example.
let A = {};
A.b =2;
console.log(A.b);
This time it works ..... because we have explicitly told it so and who decided we can tell it in this case but not in previous case. Again people who make JavaScript and html standards.
I hope we are on this lets complicate it further
let A = {};
A.attribute ={};
A.attribute.b=5;
console.log(A.attribute.b); // will work
console.log(A.b); // will not work
What we have done is tree of sorts level 1 then sub levels of non-singular object. Unless you know what is where and and call it so it will work else no.
This is what goes on with HTMLDOM when its parsed and painted a DOm tree is created for each and every HTML ELEMENT. Each has level of properties per say. Some are predefined and some are not. This is where ID and VALUE bits come on.
Behind the scene they are mapped on 1:1 between level 1 property and sun level property aka attributes. Thus changing one changes the other. This is were object getter ans setter scheme of things plays role.
let A = {
attribute :{
id:'',
value:''
},
getAttributes: function (n) {
return this.attribute[n];
},
setAttributes: function (n,nn){
this.attribute[n] = nn;
if(this[n]) this[n] = nn;
},
id:'',
value:''
};
A.id = 5;
console.log(A.id);
console.log(A.getAttributes('id'));
A.setAttributes('id',7)
console.log(A.id);
console.log(A.getAttributes('id'));
A.setAttributes('ids',7)
console.log(A.ids);
console.log(A.getAttributes('ids'));
A.idsss=7;
console.log(A.idsss);
console.log(A.getAttributes('idsss'));
This is the point as shown above ELEMENTS has another set of so called property list attributes and it has its own main properties. there some predefined properties between the two and are mapped as 1:1 e.g. ID is common to every one but value is not nor is src. when the parser reaches that point it simply pulls up dictionary as to what to when such and such are present.
All elements have properties and attributes and some of the items between them are common. What is common in one is not common in another.
In old days of HTML3 and what not we worked with html first then on to JS. Now days its other way around and so has using inline onlclick become such an abomination. Things have moved forward in HTML5 where there are many property lists accessible as collection e.g. class, style. In old days color was a property now that is moved to css for handling is no longer valid attribute.
Element.attributes is sub property list with in Element property.
Unless you could change the getter and setter of Element property which is almost high unlikely as it would break hell on all functionality is usually not writable off the bat just because we defined something as A.item does not necessarily mean Js engine will also run another line of function to add it into Element.attributes.item.
I hope this gives some headway clarification as to what is what.
Just for the sake of this I tried Element.prototype.setAttribute with custom function it just broke loose whole thing all together, as it overrode native bunch of functions that set attribute function was playing behind the scene.
Adding 2 more points related to .textContent and .innerHTML
<div id="mydiv"></div>
var elem = document.getElementById("mydiv");
elem.textContent = "hello"; // OK - Content has been updated
elem.setAttribute("textContent", "hello"); // NOT OK - You are trying to set
// the attribute than it's content
elem.innerHTML = "world"; // OK - Content has been updated
elem.setAttribute("innerHTML", "world"); // NOT OK - You are trying to set
// the attribute than it's content
One difference between the two is that setAttribute, when used to set the value of an <input/> will make that the default value when you call .reset() on the form it's part of, but .value = will not do this.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
Note that if setAttribute() is called to set the value of a particular attribute, a subsequent call to reset() won’t reset the attribute to its default value, but instead will keep the attribute at whatever value the setAttribute() call set it to.
If the element you are referring to does not already include a Javascript object property for a given attribute (as others have described), then setting that property will not propagate the change back to the DOM, it just adds the named property to the Javascript object, and the DOM ignores it. For example, getting the element mySpan by id and then doing mySpan.class = 'warning' will do nothing, whether or not the span element in question already has a class attribute defined, because mySpan.class is not defined in the Javascript object for a span element. You have to use mySpan.setAttribute('class', 'warning').
However a second nuance is that setting the Javascript object's innerHTML property using mySpan.setAttribute("innerHTML", someHTML) does not update the content of the element. I don't know how Javascript even catches mySpan.innerHTML = something, and calls the HTML parser, but there's some magic going on under the hood.

Categories

Resources