Conditional Attributes
Currently I cannot use a @if conditional around a html attribute
<div @if(comment.parentComment() != null)
x-init="$dispatch('${comment.parentComment().toString()}')"
@endif
>
I get the following exception:
CommentComponent.jte, error at line 9: Illegal HTML attribute name @if(comment.parentComment()! @if expressions in HTML attribute names are not allowed. In case you're trying to optimize the generated output, smart attributes will do just that: https://jte.gg/html-rendering/#smart-attributes
I really would like to do that as I don't necessarily want to put my alpine.js code into my java code and instead put it into my template.
If the attribute value is null, it will be omitted, hope that helps.
If the attribute value is null, it will be omitted, hope that helps.
Yes I know that but I would need to put the if else in a ternary operator which is uglier imo.
@casid If you think this is ok/possible I could take a crack at changing the behaviour. Or is there a certain reason why the behaviour is as it is?
@tschuehly this is because jte by default only allows writing into safe slots of a template. The parser expects to find an attribute name within this div. This needs to be done in order to decide how to escape the attribute content, which is a safe slot to write to. Having logical expressions in here would let the complexity of the parser explode, and also make it impossible to guarantee properly escaped templates.
@tschuehly this is because jte by default only allows writing into safe slots of a template. The parser expects to find an attribute name within this div. This needs to be done in order to decide how to escape the attribute content, which is a safe slot to write to. Having logical expressions in here would let the complexity of the parser explode, and also make it impossible to guarantee properly escaped templates.
Is there a way to extend the parser? So I could write a plugin where I could implement that behaviour?
No there is not. The parser is already quite complex and I fear opening this rabbit hole would make everything a lot harder to maintain, while the benefit to it is rather low. The risk on the other hand quite high, to accidentially introduce unsafe behavior or break user code.
How about using a special constant OMIT that would remove the attribute from the output if it is encountered? Similar to the poison pill pattern. Then you could write it like this.
<div x-init="comment.parentComment() == null ? OMIT : $dispatch('${comment.parentComment().toString()}')">
This constant already exists: null
I stumbled upon the same issue and I'm not able to find a working solution. I tried following variants:
@ifinside the attribute
<input id="${field.id()}" name="${field.name()}" type="${field.type()}"
value="${field.stringValue()}"
required="${field.validation().notNull()}"
oninvalid="@if (field.validation().notNull()) this.setCustomValidity('${field.validation().notNullMessage()}') @endif"
oninput="@if (field.validation().notNull()) this.setCustomValidity('') @endif"/>
which gives the following output when the field is false
<input id="name" name="name" type="TEXT" value="" oninvalid="" oninput="">
and this output when the field is true
<input id="name2" name="name2" type="TEXT" value="" required="" oninvalid=" this.setCustomValidity('Please provide a name') " oninput=" this.setCustomValidity('') ">
- Ternary operator in 'java' code:
<input id="${field.id()}" name="${field.name()}" type="${field.type()}"
value="${field.stringValue()}"
required="${field.validation().notNull()}"
oninvalid="${field.validation().notNull() ? "this.setCustomValidity('${field.validation().notNullMessage()}')" : null}"
oninput="${field.validation().notNull() ? "this.setCustomValidity('')" : null}"/>
which gives the following output when the field is false
<input id="name" name="name" type="TEXT" value="" oninvalid="">
and this output when the field is true
<input id="name" name="name" type="TEXT" value="" required="" oninvalid="this.setCustomValidity(\x27\x24{field.validation().notNullMessage()}\x27)" oninput="this.setCustomValidity(\x27\x27)">
I was trying to come up with another solution, but I was not able to find it.
Could you please help me modify my code so that it gives me the desired result -
when the field is false I expect the attributes to be omitted:
<input id="name" name="name" type="TEXT" value="">
and when the field is true I expect the attributes to have correctly escaped the values:
<input id="name2" name="name2" type="TEXT" value="" required="" oninvalid="this.setCustomValidity('Please provide a name')" oninput="this.setCustomValidity('')">
The 1. solution is the closest to the desired result, but the attributes are there with empty values when I expect them to be gone and when they're present they have empty spaces before and after (most probably is the first space after @if (field.validation().notNull()) and the second the space before @endif).
@vasekbrychta Usually I use a dedicated method like you did for some attributes. For example:
<input id="${field.id()}" name="${field.name()}" type="${field.type()}"
value="${field.stringValue()}"
required="${field.required()}"
oninvalid="${field.onInvalid("this.setCustomValidity('${field.validation().notNullMessage()}')"}"
oninput="${field.onInput("this.setCustomValidity('')")}"/>
This way you condition is directly in your Java model. This makes reading even easier.
I don't think I follow - let's take the most complicated case of oninvalid="this.setCustomValidity('Please provide a name')":
- the part
Please provide a namecannot be trusted and needs to be escaped properly (that's the partfield.validation().notNullMessage()that can contain anything from the user) - the part
this.setCustomValidity('...')is a trusted javascript call inside the template that should take the 1. part as an argument
I tried your solution oninvalid="${field.onInvalid("this.setCustomValidity('${field.validation().notNullMessage()}')"}" with onInvalid method being
public String onInvalid(String s) {
if (required)
return s;
return null;
}
and the result is oninvalid="" when the method returns null and oninvalid="this.setCustomValidity(\x27\x24{field.validation().notNullMessage()}\x27)" otherwise. The oninput attribute is properly gone when null is returned - I have no clue what is the difference between these two cases. But I might miss some important part, this is my first day experimenting with JTE.