How to generate DOM nodes with valueless attributes - javascript

I'm trying to generate nodes like this:
<div layout horizontal></div>
using DOM API.
I'm trying something like this:
var d = document.createElement("div");
d.setAttribute(...);
but never really managed to generate what I want. Any ideas how to do this?
Thanks.

The subject of your question reflects the basic confusion here. There is no such things as a "valueless attribute". There is merely a syntactic convenience available in HTML to write an attribute with no specific value, in cases where the mere presence of the attribute means something, whatever its value.
So you could write <input required> or <input required='true'> or <input required='false'> or <input required='notrequired'> and it would mean exactly the same thing (which is that input is required).
When you try to "print", in your words, the "valueless" attribute, whoever is responsible for the "printing" may choose to "be nice to you" and represent the attribute with no value, rather than showing the empty string. However, this does not change the fact that the attribute does have a value of the empty string, as can be seen easily by taking elt.getAttribute and examining the attribute value directly.
For instance, if I create a new div, then set its inner HTML to <input required="">, then certain environments, such as Chrome devtools, will show the element as <input required> rather than <input required="">. It's just syntactic sugar on both the way in and the way out, in other words.
Once I've created an element with a "valueless" attribute, which is actually an empty string, perhaps I can then make it truly valueless by setting the attribute value to null? Nope. elt.setAttribute('required', null) merely sets the attribute value to the string "null". Same for undefined.
Note that the DOM specification specifies an attribute of specified on Attr objects. However, as far as I can tell, this does not seem to be used, in the sense that, an attribute created by document.createAttribute always gets specified set to true, an attribute created by parsing HTML as in x.innerHTML = '<input required>'; always gets specified set to true, etc. And specified is marked readonly, so there's no way to examine what the effects of setting it to false would be anyway.
Anyway, what is your objective here? Why do you think you need to do this?

Just set an attribute to the empty string.
element.setAttribute('hidden', '')

You are looking for the createAttribute() and setAttributeNode() methods.
var elelement = document.createElement('div'),
var attribute = document.createAttribute('layout');
var attribute2 = document.createAttribute('horizontal');
element.setAttributeNode(attribute);
element.setAttributeNode(attribute2);

You can use setAttributeNode method of the element to append attribute node created with createAttribute:
var el = document.createElement('div'),
attr = document.createAttribute('layout');
el.setAttributeNode(attr);

Related

Changing inner text value of tab through javascript

I'm learning Javascript right now, and attempting to change the text title of a particular tab. It's actually part of a larger Shiny dashboard project, but I want to add some custom functionality to a few tabs. Below are the tabs in question:
Simple enough. I first access my tabs in my Javascript file:
var tabScrub2 = $(document).find('[data-value="scrubTab2"]');
console.log(tabScrub2);
When I use Firefox's developer console, I see that the tab is an object:
Moreover, it looks like I need to change the innerText property of 0, whatever this is, since that corresponds to the title of my tab (the innerText of 1 corresponds to the text inside scrubTab2). However, I'm not familiar with the actual object type being returned here:
Simply put, how the heck do I access and manipulate properties from this? And am I actually accessing an array? When I type in
var scrub2 = tabScrub2["1"];
console.log(scrub2);
I get an HTML element. I'm seen the a element in CSS and jQuery, but am not super familiar with how to manipulate its properties programmatically? How do I go about accessing and manipulating the innerText properties of this via Javascript? For instance, how would I hide scrubTab2, or change its title to something else?
The first object you're seeing is jQuery's wrapper around the real DOM elements. It's not an actual array, but it does contain all of the elements that matched your query under zero-indexed properties (e.g. "0" and "1") which allows you to access to them via an array-like API (e.g. tabScrub[1]).
Your method of grabbing a node using tabScrub2["1"] is correct (see this question in the jQuery FAQ). It's more likely to see that done with a numeric key though (i.e. tabScrub[1]) because that matches the way you would access an element in a normal array.
As far as manipulating properties of the DOM node, the DOM's API is notoriously inconsistent and quirky (hence the need for things like jQuery in the first place). However, for your use case you can just assign a string to the innerText property directly (e.g. tagScrub2[1].innerText = "Tab title"). MDN is a great resource if you're looking for reference material on other parts of the DOM.
A side note: if you're looking for a specific element you should use a query that will only match that element. It's generally a bad sign if you're grabbing extra elements and then accessing the element you want at a key other than 0. If you're doing this then your code depends on other (potentially unrelated) nodes in the DOM existing before your node, and if/when you change those nodes your original code will break.
Just use jQuery eq method to get the relevant object index from the array.
For an example
//Query and get first element.
var tabScrub2 = $(document).find('[data-value="scrubTab2"]:eq(0)');
//Hide
tabScrub2.hide();
//Change title
tabScrub2.attr("title", "New Title Text");
Lean more about jQuery eq here.
https://api.jquery.com/eq/
Since you use jquery selectors tabScrub2[0] returns the native DOM element instead of another jQuery object. Therefore the hide function won't work in that object since the native DOM element doesn't implement such type of functionality for an element. That's why you have to use jQuery pseudo selector as above. Because hide will only work with a jQuery object.

Is it possible to change dom-element property types? (Number, String etc.)

Consider an input field
<input type="number" id="output" disabled="true">
is something like this possible ?
var output = Document.getElementById("output");
output.value = Number(0);
I tested it and it has no effect (+= operator is still concating strings). Is there a way to change the variable type of a dom-element property?
What exactly happens in the line
Document.getElementById("output").value = Number(0);
and why does it have no effect on the type?
Does this apply to Dom-objects only or are there other cases that this invariability also applies to (or were I can actively define it for a variable)?
PS: I know I can simply use a temporary variable to avoid problems like this in general, but I want to know why the DOM property is unaffected by output.value = Number(0);
Instead of assigning a value directly to a DOM element attribute you should use the setAttribute function of the element.
var output = Document.getElementById("output");
output.setAttribute('value',Number(0));
why does it have no effect on the type?
The DOM element's attributes are part of the HTML and because of the HTML structure all the attribute values should always be quoted (https://www.w3.org/TR/xhtml1/diffs.html#h-4.4), therefore for any value that you set for a property it will be stored as a string.
This means that even if you're explicitly giving the value Number(0) for the atribute 'value' at the end it will be stored in the HTML structure like this:
<input type="number" id="output" disabled="true" value="0"/>
And as you can see it is quoted, this is the string representation of the attribute value, for a 0 the string representation is "0", if you try to set an attribute with another type e.g an object, you will have something like this.
//setting a custom attribute the value: {a:10}
document.getElementById('output').setAttribute('myattr',{a:10})
HTML:
<input type="number" id="output" disabled="true" myattr="[object Object]">

Calling Method faster then Retrieving Something From Memory

So this is my question: Why would calling a method be faster then retrieving something from memory?
Noticed when an id attribute is specified on a DOM element, user agents automatically attach the element's reference on their global scope.
Since user agents already reference all elements, which have their id attribute specified, why would I need to use document.getElementById("")?
Within an application, I would:
//Retrieving the value, I could possibly write this two way.
<script>
var fromGlobalScope = myElement.value;
var documentGetById = document.getElementById("myElement").value;
</script>
<input id="myElement" value="someValue" />
Doing some research, it is supported by all major browser, but their may some browser that do not support, which will break.
However, I could simply write:
<script>
//See if the element is on the global scope.
var fromGlobalScope = myElement ||document.getElementById("myElement");
</script>
I believe patterned correctly, I can automatically have references to all elements that have an id attribute. I don't have to call document.getElementById();
Using an resident property and I wouldn't have to walk the DOM, would think there would be a good performance benefit.
I created a jsPerf to see the benefit: enter link description here
My surprise was using document.getElementById() was a lot faster?
So this is my question: Why would calling a method be faster then retrieving something from memory?
Using document.getElementById, I would be calling a method that may or may not walk the DOM. At least, I will be calling an address for the value.
With a property on the global scope that should be quickly available as it is placed in some memory location.
I have include jsPerf results below:
I created another jsPerf with another thought:
explicitly setting a property on the window object
However, I still believe learning why can help with the mechanics that are at play, which may result in something helpful.
From HTML5 spec
5.2.4 Named access on the Window object
The Window interface supports named properties. The supported property
names at any moment consist of the following, in tree order, ignoring
later duplicates:
the browsing context name of any child browsing context of the active document whose name is not the empty string,
the value of the name content attribute for all a, applet, area, embed, form, frameset, img, and object elements in the active document that have a non-empty name content attribute, and
the value of the id content attribute of any HTML element in the active document with a non-empty id content attribute.
So the browser will probably walk the DOM tree to resolve a named property. In contrast getElementById() just needs to look the id up in (say) a hash map.
While the browser could maintain a hash map of the first matching element to that algorithm, maintaining that map would impose a performance penalty that would rarely pay for itself. In contrast the browser is looking up elements by their id constantly, so it pays to keep the id map.

Setting a property via property or setAttribute

Is one of these more preferable than the other? Why? How about performance--if these are being called thousands of times?
A) element.setAttribute("disabled", true);
B) element.disabled = true;
They both seem to disable an input[text] element in FF 4.
In general…
Use properties. For a long time (until version 7 or 8 IIRC) Internet Explorer had a seriously broken implementation of setAttribute that would set the property not the attribute (the classic point of failure was class since there is no class property (it is className).
In this case in particular… element.setAttribute("disabled", true); is wrong. It should be element.setAttribute("disabled", "disabled");
element.setAttribute("disabled", some_bool) doesn't work like you'd think it will. In particular, standardswise, disabled is what's known as a boolean attribute; its very presence, regardless of its value, makes it true. disabled="", disabled="disabled", disabled="true" and even disabled="false"(!!!) all mean the same thing in most browsers. (Although the last two are actually invalid HTML, most browsers will consider them equivalent to disabled="disabled" for truth purposes. Including every one of the Big Four.) You set a boolean attribute to true by setting a value -- any value, even if it's falsy -- and you set it to false by removing the attribute entirely.
If you care about the actual string value of the attribute (which in this case you shouldn't), and particularly if the attribute isn't already exposed via the DOM (that is, it doesn't have a corresponding property), then use (get/set)Attribute. In most cases (particularly if you care about how it affects the element, like in this case where you're trying to disable an element), use the DOM property.
IE needs some attributes to be set with setAttribute, but not all. I don't have a list though, you just have to check if it works or not. Also, using setAttribute will put the attribute in the DOM, so it can be shown when doing view source.
Only one tip: element.setAttribute('class',xxx) doesnt works in some versions of IE.
Prefer element.className = xxx instead

How to add/update an attribute to an HTML element using JavaScript?

I'm trying to find a way that will add / update attribute using JavaScript. I know I can do it with setAttribute() function but that doesn't work in IE.
You can read here about the behaviour of attributes in many different browsers, including IE.
element.setAttribute() should do the trick, even in IE. Did you try it? If it doesn't work, then maybe
element.attributeName = 'value' might work.
What seems easy is actually tricky if you want to be completely compatible.
var e = document.createElement('div');
Let's say you have an id of 'div1' to add.
e['id'] = 'div1';
e.id = 'div1';
e.attributes['id'] = 'div1';
e.createAttribute('id','div1')
These will all work except the last in IE 5.5 (which is ancient history at this point but still is XP's default with no updates).
But there are contingencies, of course.
Will not work in IE prior to 8:e.attributes['style']
Will not error but won't actually set the class, it must be className:e['class'] .
However, if you're using attributes then this WILL work:e.attributes['class']
In summary, think of attributes as literal and object-oriented.
In literal, you just want it to spit out x='y' and not think about it. This is what attributes, setAttribute, createAttribute is for (except for IE's style exception). But because these are really objects things can get confused.
Since you are going to the trouble of properly creating a DOM element instead of jQuery innerHTML slop, I would treat it like one and stick with the e.className = 'fooClass' and e.id = 'fooID'. This is a design preference, but in this instance trying to treat is as anything other than an object works against you.
It will never backfire on you like the other methods might, just be aware of class being className and style being an object so it's style.width not style="width:50px". Also remember tagName but this is already set by createElement so you shouldn't need to worry about it.
This was longer than I wanted, but CSS manipulation in JS is tricky business.
Obligatory jQuery solution. Finds and sets the title attribute to foo. Note this selects a single element since I'm doing it by id, but you could easily set the same attribute on a collection by changing the selector.
$('#element').attr( 'title', 'foo' );
What do you want to do with the attribute? Is it an html attribute or something of your own?
Most of the time you can simply address it as a property: want to set a title on an element? element.title = "foo" will do it.
For your own custom JS attributes the DOM is naturally extensible (aka expando=true), the simple upshot of which is that you can do element.myCustomFlag = foo and subsequently read it without issue.

Categories

Resources