This question already has answers here:
Are empty HTML data attributes valid?
(4 answers)
Closed 7 years ago.
I am wondering if html data attributes actually need a value to be applied?
I wonder this because often all we want to know is if the attribute is actually set to act as a flag. (sure we could use a class for this; but realistically unless you are going to style these items differently then the flags are more data than a semantic item).
A perfect example of this is if we want a link to scroll to it's target instead of jumping our jQuery code might look like:
$(document).on('click', '[data-scroll-link'], function(){/**do scroll**/});
I know in google chrome it is sufficient for the anchor to appear as
<a href="#bottom" data-scroll-link>Scroll to bottom</a>
But will that work everywhere? and is it even valid HTML5 (I believe it is due to the autofocus, autoplay etc attributes). or do we need:
Scroll to bottom
No. But...
As is common with all attributes, in the application/xhtml+xml serialisation, XML rules apply and the attribute must have an explicit name and (quoted) value.
So this question is really about the text/html serialisation, and therefore the relevant part of the HTML5 spec is Section 8 The HTML syntax
In particular, under attributes, it says:
Attributes can be specified in four different ways:
where the first of these is:
Empty attribute syntax
Just the attribute name. The value is implicitly the empty string.
It's necessary to understand though that the value is of string type, not of boolean type.
For example, with <input id="cb" type="checkbox" checked>, the "checked" attribute is reflected by a property that is either true or false. So
if (document.getElementById("cb").checked)
will evaluate to true for the above markup.
In contrast, with <input id="cb" type="checkbox" data-checked>, the "data-checked" attribute is reflected via the dataset object as a string. The value of this property is the empty string, which in JavaScript is falsey. So,
if (document.getElementById("cb").dataset.checked)
will evaluate to false for the above markup.
To do the equivalent test, compare the value for "not undefined". I.e.
if (document.getElementById("cb").dataset.checked !== undefined)
will evaluate to true for the above markup.
See http://jsfiddle.net/GAxvW/
Simple Boolean Test For Element Attributes
To expand on Alohci's excellent answer, the following is a simple, flexible way to test for a true boolean attribute value supplied using one of three standard HTML conventions: <foo data-bar/>, <foo data-bar="true"/>, or <foo data-bar="data-bar"/>.
var a = elem['data-bar'];
var aTrue = ( a != null && a !== false && a !== 0 && a.charAt(0) != 'f' &&
a.charAt(0) != 'n' );
With the code above, the value is false if undefined or set to one of: f*, n*, 0 (case-insensitive), and true if defined and set to one of: (empty string), (attribute name), (anything else).
Empty strings are evaluated to true here because HTML attributes without values are '' which equal false in JS (and something like <foo disabled/> should equal <foo disabled="true"/>). You can use the above code for more general string testing by removing != null && a !== false.
Related
I'm reading the Vuejs docs and get confused at some point when I was at the part of Attribute Bindings (link to the specific part : https://vuejs.org/guide/essentials/template-syntax.html#boolean-attributes).
As far as I'm aware, in JavaScript, empty strings ("") are considered as falsy.
But, in Vuejs Docs:
<button :disabled="isButtonDisabled">Button</button>
The disabled attribute will be included if isButtonDisabled has a truthy value. It will also be included if the value is an empty string, maintaining consistency with <button disabled="">. For other falsy values the attribute will be omitted.
Here, they evaluate the empty string as a truthy value !
If someone has an explanation ? it's something that we should be aware of, or it's just a choice of Evan You (creator of Vuejs), but based on what ?
Thanks.
An empty string as value for the disabled HTML attribute, on elements which support it, is interpreted as a truthy value. This is the HTML standard.
<input disabled />
<!-- exact equivalent of... -->
<input disabled="" />
<!-- exact equivalent of (in Vue template) -->
<input :disabled='""' />
<!-- exact equivalent of (in JSX) -->
<input disabled={""} />
When provided as a binding JavaScript expression, Vue will not include the attribute when the expression is falsy, except when it evaluates to empty string. In that case, Vue will include the attribute, without changing its value.
Why is the warning there?
Because empty string is typically interpreted as falsy value in JavaScript and they identified this as a potential source of subtle bugs
The attribute's behavior is not Vue team's decision. It's W3C's decision.
So yeah, you can say it's "official". It can't get any more "official" than that.
I'm rather new to this and don't know exactly how to report a bug, but I first want to confirm it's a bug and then go on from there. But here's what I'm finding:
1) When creating an audio object controls attribute, the controls attribute will respond to a string as if it's a boolean.
For Instance:
<button onclick="example()">Try this</button>
<script>
function example() {
var aud = document.createElement("AUDIO");
aud.setAttribute("src","example.mp3");
aud.setAttribute("controls", "controls");
}
Okay, we've put controls in there because it makes controls equal controls:
Thing is, you can put any old string in there and it works just fine -- apple, banana, pear, anything.
2) Isn't the value suppose to be a boolean? Well when you try a boolean, false for example, you still get true. (False == True) It works just as if you typed in true.
...and if you put anything else other than true or false (just type anything other than an integer, string, or true or false value), you get false (or it just doesn't work).
Everything equals true and a non-string, non-integer equals false (or just doesn't work).
Finally, you can even try setting the controls attribute on an accessed audio element:
var aud = document.getElementById("idhere");
function accessAudioElement() {
aud.controls = false;
}
At least here the true and false actually work as true and false, but once again, any string or integer will also get you true and any non-string/non-integer will break the code.
Can somebody help me out here because I don't think this is suppose to work this way... and if does, what's the point of using a boolean value when most anything else will work?
Of course I'm still learning, so maybe this is not a bug, maybe for some reason this is suppose to work this way, but if that's the case would someone please share the logic behind this with me.
I'm just not understanding.
Thanks Magic
This is an extended answer of what #nnnnnn suggested in the comments.
aud.controls = false; doesn't set the attribute, it sets the property.
You need to use setAttribute() method to add the specified attribute to an element.
aud.setAttribute("controls", "controls");
And use removeAttribute() method removes the specified attribute from an element.
aud.removeAttribute("controls");
For more reading on these methods, have a look at the hyperlinks attached.
Element.setAttribute()
Element.removeAttribute()
When to use setAttribute vs .attribute= in JavaScript?
HTML - attributes vs properties
You might want to read/search more about Javascript Truthy $ Falsey. It is very important.
https://j11y.io/javascript/truthy-falsey/
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);
I have data attributes I'm using for options on a table, for example:
<table data-do-something-neat>
...
</table>
I'm using HAML to define them:
%table{ data: { do_something_neat: true } }
...
In HAML it's an HTML5 formatted page, so it's behavior is to drop the value if it's a boolean and true. If it were set to false, it would be gone, like so:
<table>
...
</table>
All this seems fine, but accessing whether that flag is true or false in jQuery is a bit of a pain, and I can't find any definitive reference on how to do it.
For the first table, the following is true:
table.is('[data-do-something-neat]') # true
table.attr('data-do-something-neat') # '' (empty string)
table.data('do-something-neat') # '' (empty string)
And for the second table:
table.is('[data-do-something-neat]') # false
table.attr('data-do-something-neat') # undefined
table.data('do-something-neat') # undefined
So attr and data return something falsy for a true HTML5 data attribute. Is this expected? Is there another data method that could be used? Or am I stuck using is in this way? It's unfortunate to have to use a special method for boolean attributes, instead of just using data for all data attributes.
It kind of makes sense that you're stuck using .is(). Some data attributes should be treated as Booleans, and some should be treated as strings.
Imagine if attr() returned true for an empty string; it would be difficult to test for, and in order to have it properly appear as 'null', your server code would need to write:
<table
<?php if $accountId != null {?>
data-accountId="<?php echo $accountId; ?>"
<?php } ?> >
(The emphasis being on the outside null-checking condition). But, since it returns an empty string, you can simply use javascript and use any standard "is empty string" method you prefer, or just check "if length == 0" if you know the attribute should always be printed from the server.
The difference is that if the attribute is not there, $.attr and $.data return undefined, if it's there without a value, it returns an empty string, which is the expected behavior, as far as I know.
What is the problem with checking?
if (typeof table.attr('data-do-something-neat') !== 'undefined') {
// attribute exists, but it could be the empty string
}
If you want a more straight forward way to test it, you can use Element.hasAttribute
if (table[0].hasAttribute('data-do-something-neat')) {
// attribute exists, but it could be the empty string
}
I would just use a selector and check for the existance of a correctly selected element:
$('table[data-do-something-neat]').length !== 0
or
$('#A').attr('myattr') !== undefined // If attribute exists
That's what's noted in this SO question: Select elements by attribute
Or if you can go without jQuery there are native DOM methods that will suffice:
Element.hasAttribute('data-do-something-neat');
This question already has answers here:
Are empty HTML data attributes valid?
(4 answers)
Closed 8 years ago.
Can you use data-* attributes as boolean attributes? If not, is there an alternative?
For example, you can have
<input disabled>
It would be helpful in some cases to have
<input data-on>
Using data-on="true" or data-on="" is not desirable -- the presence of the attribute should indicate its boolean value.
You can indeed use data-* attributes as if they were boolean attributes - however, as far as dataset is concerned <input data-on> is equivalent of <input data-on="">. This means that unlike required or other boolean attributes you won't be able to do this:
<input class="some-class" data-on required>
var elementOfInterest = document.querySelector(".some-class");
if (elementOfInterest.dataset.on) {
// We will never get here because dataset.on === ""
// and "" == false
}
if (elementOfInterest.required) {
// We *do* get here because required is a boolean attribute
}
Instead you'll need to do an explicit check against undefined:
if (elementOfInterest.dataset.on !== undefined) {
// We will get here because "" !== undefined
}
This gives you no way of distinguishing between data-on and data-on="", but if you are treating it as a boolean attribute, they both add up to the same thing anyway (only the absence of the attribute indicates falsity.)
Yes, data-* attributes can function as boolean attributes, at least as far as the DOM and browser selector engines are concerned: http://jsfiddle.net/MhJNb/
I haven't tested compatibility, but Chrome has no problem with applying div[data-on] rules to <div data-on></div>.