Vuejs Boolean Attributes (Truthy and Falsy values) - javascript

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.

Related

Most efficient way co compare two DOMStrings if they represent the same DOM node in JavaScript

I use ReactJs function renderToStaticMarkup to create HTML Markup. The markup is on another place in the App set as the innerHTML property to other DOM node. Since I would like to prevent images and iframes from re-rednering, I would like to make comparison, if the current innerHTML is the different from the one it should be set to.
if (!domNode.innerHTML !== newMarkup);
domNode.innerHTML = newMarkup;
}
For some reason, Reacts renderToStaticMarkup creates HTML Markup for images as:
<img src="https://placebeard.it/200x150" alt="" class="content-media-image-linked"/>
but the DOM innerHTML has a value of
<img src="https://placebeard.it/200x150" alt="" class="content-media-image-linked">
So basically the difference IS in the trailing / (but this does not need to be the rule of thumb)
I wonder what would be the most efficient/fast way to determine, whether those two DOMStrings represent the same DOM Node.
1. String Comparison
It would be probably enough to replace/remove all occurrences of />
2. Parsing/converting to DOMNodes
This is more safe method, but also much more expensive. I would have to use something like document.createRange().createContextualFragment (see this post) and than use the isEqualNode method.
Has aonyone some better sugeestion ?
As I think you know, the / in /> at the end of a tag has no meaning whatsoever in HTML (it does in XHTML and JSX), so my temptation would be
Change the /> to > and compare; if they match, they're the same.
If they don't match, parse it and use isEqualNode
The first gives you the quick win in what I assume will be the majority case. The second works the slower but more robust way, allowing attributes to be in a different order without introducing a difference (unless it makes a difference), etc.
When replacing the /> with >, be sure of course to only do so in the right place, which may or may not be tricky depending on the strings you're dealing with (e.g., to they contain nested HTML, etc.). ("Tricky" as in "you can't just use a simple regular expression" if the HTML isn't of a single element like your img example.)
A quick fix to my issue was performing sanitization of the HTML Markup produced by the _ renderToStaticMarkup_ call. In my case the markup is generated only occasionally, but the Dom-Node equality check very often, so I went with just plain string quality-check.
I tried multiple libraries to achieve that:
sanitize-html lokked promissing, but was not removing the trailing /
html-minifier worked, but I had issues using it with es6 imports
I ended up using dompurify

Invalidating text field Angular JS [duplicate]

From the Docs:
Embedding interpolation markup inside expressions
Note: AngularJS directive attributes take either expressions or interpolation markup with embedded expressions. It is considered bad practice to embed interpolation markup inside an expression:
— AngularJS Developer Guide - Interpolation
I am looking for a well written canonical answer to which I can point readers.
From the Docs:
Why mixing interpolation and expressions is bad practice:
It increases the complexity of the markup
There is no guarantee that it works for every directive, because interpolation itself is a directive. If another directive accesses attribute data before interpolation has run, it will get the raw interpolation markup and not data.
It impacts performance, as interpolation adds another watcher to the scope.
AngularJS Developer Guide - Interpolation
Directives which expect Boolean values won't work:
ERRONEOUS
<input type="checkbox" ng-hide ="{{x.thenumber === null}}" />
When the expression evaluates to the Boolean value false, interpolation will return the string "false". Strings that have length greater than zero are truthy. The ng-hide directive will always hide and never show the input element.
CORRECT
<input type="checkbox" ng-hide="x.thenumber === null" />

React inline conditional component attribute

I've been searching everywhere and can't find an answer to my question. So I want a conditional attribute which is only displayed on certain conditions, example:
<Button {this.state.view === 'default' && 'active'}></Button>
As you can see I only want to indicate the button active if the this.state.view is equal to default. However, I get Unexpected token, error...
But when I try to put an attribute before it, for example:
<Button isActive={this.state.view === 'default' && 'active'}></Button>
It passes the syntax error and displays fine but this is not what I wanted to achieve.
How can I fix this? And what could be the reason behind it not passing?
UPDATE
So I just found out that in react-bootstrap the property active is a shorthand of active=true so I solved it using
<Button active={this.state.view === 'default'}></Button>
So In case, someone encounters this problem I'm leaving it here. However, I still want to know why the conditional attribute is failing without enclosing it inside a prop-like syntax, example:
This:
active={this.state.view === 'default'}
Versus
{this.state.view === 'default' && 'active'}
First of all, JSX is just a syntactic sugar for React.createElement. So, it may look like, but, in reality, you don't specify html attributes: in fact, you are always passing props.
For instance, the JSX code <input type="button" value="My button" /> is transpiled into React.createElement('input',{type:'button',value:'My Button'}). And, when necessary, React engine renders this React Element to the DOM as a HTML element.
That said, we have that JSX transpiles a prop without a value as true (check docs). For instance: <Button active></Button> is transpiled to React.createElement(Button, { active: true });.
But, we know that HTML5 specification does not accept attribute=true (as pointed here). For instance: <button disabled=true></button> is invalid. The correct is <button disabled></button>.
So, to render the HTML element to the DOM, React considers only props that are valid attributes (if not, the attribute is not rendered). Check all supported html attributes. And, then, finally, if it's a boolean attribute, it removes the true/false value, rendering it properly.
For instance: <button active={true}></button> is transpiled to React.createElement("button", { active: true }); and then React renders to the DOM <button></button>, because there is no active attribute in HTML specification for the <button/> tag (is not in the supported attributes list).
But <button disabled={true}></button> is transpiled to React.createElement("button", { disabled: true }); and React renders to the DOM <button disabled></button>.
I just said that to clarify your case.
You're trying to pass an active prop to the Button component (first letter uppercase means that's a React component: there is a React Component called Button handled somewhere in your code).
That means:
<Button active></Button> is transpiled to React.createElement(Button, { active: true });
and
<Button active={true}></Button> is transpiled to React.createElement(Button, { active: true });
The same thing!
So, if you want to do a conditional prop, you can simply do something like that:
<Button active={this.state.view === 'default'}></Button>
You have a condition inside brackets. Means that, if your this.state.view is equal to default (true), active prop will be passwed down to the component with the true value. If not equal, with the false value.
Button Component, then, must someway handle this active prop. It can render the button element and, for instance, change it's style, pass the disabled prop... I created a fiddle to demonstrate this: https://jsfiddle.net/mrlew/5rsx40gu/
Actually, I guess it is a duplicated question that I answered it in this link sometimes ago. for this specific post, there is no need condition prop for a boolean value, because it works well like below:
const { booleanValue } = this.props;
return (
<input checked={booleanValue} />
);
Or make your own boolean value:
const booleanValue = someThing === someOtherThing;
return (
<input checked={booleanValue} />
);
Both of them work well, because when the booleanValue is false, react doesn't see the active prop, hence it does not exist, unless you pass checked prop to a specific component that the component will receive false checked prop from this.props.
But, if you wanna a have a prop on your specific component with a condition and if the condition returns false you don't want it there are two ways, I like second:
First:
<Component someProp={condition ? yourValue : undefined} />
Second:
<Component {...(condition && { someProp: yourValue })} />
In JSX, component properties (or props) compile to a plain JavaScript object. Prop names are used as the keys of the object, and prop values are stored under those keys. The first example from the JSX docs does a great good job demonstrating this. In your case {view === 'default' && true} is a raw value without an associated prop name. Without a prop name to use as a key (specified by the syntax name=), JSX has nowhere to put that value in the final props object.
However, JSX will accept props via your original syntax if the expression inside the curly braces evaluates to an object. For example, you could do {{ active: view === "default" }}. In this case JSX can get both the key and value that it needs from the provided object, so no active= is necessary.

How to generate DOM nodes with valueless attributes

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);

Do html5 data attributes need a value? [duplicate]

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.

Categories

Resources