Smarter attributes coming to Latte
- David Grudl
- Nette Core | 8282
I want to introduce new features for attribute rendering in Latte that will make working with templates easier and more type-safe. The main goal is to solve common issues with attribute rendering while preserving backward compatibility for existing code.
Boolean in attribute
<div foo="{$val}">
If $val
is a string or number, it's clear what gets rendered.
But what happens when $val contains a boolean?
<div foo="{=true}" bar="{=false}">
// renders as: <div foo="1" bar="">
This isn't ideal, because this behavior is rarely useful in practice
I therefore plan to release a version that will throw warnings if an attribute value is boolean (or array, see below), indicating that this type is not supported. The warning will directly reference the template name and line number.
Exception: boolean attributes
Boolean attributes (like checked
or hidden
) will
accept boolean values. The value determines whether the attribute gets rendered
or not (based on whether it's truthy):
<input hidden="{=true}" readonly="{=false}">
// renders as: <input hidden>
This behavioral change isn't a BC break, because currently it doesn't make sense for anyone to combine a boolean attribute with any value in a template.
Aria attributes
Another exception would be aria-attributes, where I want boolean attributes to be
output as true
and false
, because they work with these
values:
<button aria-expanded="{=true}" aria-checked="{=false}">
// renders as: <button aria-expanded="true" aria-checked="false">
Again, I believe this isn't a BC break, because currently it doesn't make sense for anyone to combine an aria attribute with a bool value in a template.
Data attributes
It might be useful if data-attributes behaved similarly to aria-attributes,
i.e., that bool values would be accepted and output as true
and
false
. But that would already represent a BC break. Therefore
data-attributes don't represent any exception and will throw warnings.
I can imagine that the current behavior, where boolean gets typecast to
"1"
or ""
, works for you with data-attributes, that
you rely on it. Then it's easiest to work around this by typecasting the value
to string <div data-foo="{(string) $val}">
. I understand
that this is a case where this change would require some additional work.
If you'd instead want to go the route of true
and
false
values, the easiest approach is probably to create a filter
for it. I'm considering adding something like this to the standard toolkit.
Array in attribute
What happens when we try to pass an array into an attribute?
<div foo="{[]}">
// renders as: <div foo="Array">
In the new version, besides Latte throwing warnings when there's an array in
an attribute value, I want such attributes not to render at all, because
foo="Array"
is never useful.
However, arrays will be allowed for style
attributes:
<div style={[ backgroundColor: 'lightblue', fontSize: '16px' ]}>
// renders: <div style="background-color: lightblue; font-size: 16px">
Also for attributes that expect a space-separated list, like
class
(which actually makes it equivalent to
n:class
):
<div class={[ first: true, last: false, always ]}>
// renders: <div class="first always">
And finally for all data-*
attributes, where it will serialize
as JSON:
<div data-config={[ theme: 'dark', version: 2 ]}>
// renders: <div data-config='{"theme":"dark","version":2}'>
n:attr
The goal is also to completely unify how attributes are rendered using the
n:attr
tag with how they're rendered when we write them directly in
template code.
Optional attributes
I'd like to eventually achieve more flexible conditional attribute rendering in the future. It would be possible to easily write data-attributes where the value would determine their presence or absence, so they would actually function like boolean attributes.
However, this is more complex from a compatibility standpoint, so I'll create a separate thread for that.