nanohtml
nanohtml copied to clipboard
Support && operator-based conditionals in expressions
What do you think of supporting &&
operator-based conditionals in interpolated expressions?
Current syntax:
html`<input type="checkbox" name="reviewed" ${data.reviewed ? 'checked' : ''} />`
Proposed syntax to support:
html`<input type="checkbox" name="reviewed" ${data.reviewed && 'checked'} />`
The proposed syntax is simply more succinct, and I believe it's popular in the react ecosystem. While the above example doesn't save much text, the : ''
gets in the way more when you have multi-line expressions -- it becomes a trailing piece that is often overlooked.
Currently, the proposed syntax works in bel if the first condition is truthy, but if it is falsy, bel renders its falsy value, and you'd end up with <input type="checkbox" name="reviewed" undefined />
. I believe the way around this would be for bel (or maybe hyperx?) to not return anything from an interpolated expression that evaluates to undefined
or false
. I believe this is how JSX does it.
If for some reason you want to render undefined
or false
, I think it would be reasonable to convert it to a string (since it's a string once it's in the DOM anyway). I think the exception to this would be the value 0
-- it may be unexpected to have to convert 0
to a string just to render it to the DOM. 0
comes in to play when you want to do ${rows.length && 'foo'}
vs. ${rows.length > 0 && 'foo'}
.
/cc @yoshuawuyts
I'm on board with this; seems useful enough and can't think of a reason to render the value undefined
like ever
I don't think we have much control over what happens within the expression of a template literal.
Although I think we should just make it smarter about interpreting booleans for attributes:
html`<input type="checkbox" name="reviewed" checked=${data.reviewed} />`
Would render if true
:
<input type="checkbox" name="reviewed" checked="checked" />
and if false
:
<input type="checkbox" name="reviewed" />
I agree with this issue, it is actually implemented with Babel/JSX. Those falsy values should be forgotten (not numbers):
- false
- null
- undefined
- empty string
Let's compare:
❌ html`<input value="${data.value ? data.value : ''}" />`
✅ html`<input value="${data.value}" />`
Declarative conditional
❌ html`<div>${data.alert ? html`<x-alert />` : ''}</div>`
✅ html`<div>${data.alert && html`<x-alert />}</div>`
Declarative switch case with three ternary operators
❌ html`<div>${data.option === 1 ? html`<x-option1 />` : (data.option === 2 ? html`<x-option2 />` : html`<x-option3 />`)}</div>`
✅ html`<div>
${data.option === 1 && html`<x-option1 />}
${data.option === 2 && html`<x-option2 />}
${data.option === 3 && html`<x-option3 />}
</div>`
The idea is to keep it declarative (no if/else/swtich) and lisible as possible.
What do you think?
I’m on board with this idea
Are there any advancements on this ? It seems that it is "supported" syntaxwise but a false value is rendered as the string "false".
I think that it would be best to suppress falsey outputs from the expressions - the only issue being rendering "false" from ${false}, but I think this is much less useful than the simpler conditional rendering ^^.
Thoughts ? Should be an easy fix.
I'm going to be diving back into the Choo ecosystem in a big way over the coming months. This is something I would like to see land as well.
The type tests in hyperx show that the following values will render empty:
- null
- undefined
- empty string (test is not written, but I wrote a test and will submit a PR)
0
does not render empty thankfully.
I see only two problems making this change.
- Change
false
to render empty would be a breaking change - I have no idea where in the code to make that change because the code is rather dense. So I could use a hand with that (@goto-bus-stop ?)
@mjstahl yeah, hyperx is not an easy codebase. i'd have to go in with some console.logs myself to be sure, but I think the places to look at would be the places that call strfn
and concat
. Those functions are used to stringify text and attribute values and to concatenate them if there is a ${templatePart}
inside.