quarkiverse / quarkus-renarde

Server-side Web Framework with Qute templating, magic/easier controllers, auth, reverse-routing
Apache License 2.0
78 stars 19 forks source link

Custom Tags: Issue with Boolean and NOT (!) operation #64

Closed tmulle closed 2 years ago

tmulle commented 2 years ago

Hi,

I have a custom tag which build a label and a textfield with a variety of parameters. One of those being the ability to disable the field with the 'disabled' parameter.

I'm getting an error when trying to pass in a boolean and take the opposite of it using the (!) operation. You can see in the error message below that the canEdit parameter is included in the list of params available to the template.

In my Templates instance I have the method defined as: public static native TemplateInstance orgEdit(OrgFormData orgForm, Long orgId, boolean canEdit);

If I take out the (!) and just make it disabled=canEdit the build succeeds but then my form element is always disabled.

So, I'm not sure why it's not working.. any ideas? is the boolean operation (!) supported inside custom tags?

Thanks again!

Template Use:

{#text name="name" value=orgForm.name label=i18n:['label.orgName'] placeholder="Org Name"
            label_class="control-label form-label f-required"
            input_class="form-control input-sm"
            disabled=!canEdit
          /}

text.html (Custom Tag)

<div class="form-group {#ifError name}has-error{/ifError}">
  <label class="{label_class??}" for="{name}">{label??}</label>
  <div class="mb-3">
    <input name="{name}" id="{name} type="{type ?: 'text'}"
           {#if placeholder??}placeholder="{placeholder}"{/if}
           class="{input_class??} {#ifError name}is-invalid{/ifError}"
           value="{inject:flash.get(name) ?: value??}"
           {#if readOnly??}readonly{/if}
           {#if disabled??}disabled{/if}
    />
    {#ifError name}
      <span class="has-error">​{#error name/}</span>​
    {/ifError}
  </div>
</div>

Error:

 Failed to build quarkus application: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[ERROR]         [error]: Build step io.quarkus.qute.deployment.QuteProcessor#processTemplateErrors threw an exception: io.quarkus.qute.TemplateException: Found incorrect expressions (1):
[ERROR]         [1] Orgs/orgEdit.html:162:11 - {!canEdit}: Only type-safe expressions are allowed in the checked template defined via: com.rajant.support.site.rest.Orgs$Templates.orgEdit(); an expression must be based on a checked template parameter [orgForm, canEdit, orgId], or bound via a param declaration, or the requirement must be relaxed via @CheckedTemplate(requireTypeSafeExpressions = false)
[ERROR] 
[ERROR]         at io.quarkus.qute.deployment.QuteProcessor.processTemplateErrors(QuteProcessor.java:233)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
[ERROR]         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR]         at java.base/java.lang.reflect.Method.invoke(Method.java:568)
[ERROR]         at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:909)
[ERROR]         at io.quarkus.builder.BuildContext.run(BuildContext.java:281)
[ERROR]         at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
[ERROR]         at java.base/java.lang.Thread.run(Thread.java:833)
[ERROR]         at org.jboss.threads.JBossThread.run(JBossThread.java:501)
[ERROR]         Suppressed: io.quarkus.qute.TemplateException: Orgs/orgEdit.html:162:11 - {!canEdit}: Only type-safe expressions are allowed in the checked template defined via: com.rajant.support.site.rest.Orgs$Templates.orgEdit(); an expression must be based on a checked template parameter [orgForm, canEdit, orgId], or bound via a param declaration, or the requirement must be relaxed via @CheckedTemplate(requireTypeSafeExpressions = false)
[ERROR]                 at io.quarkus.qute.TemplateException$Builder.build(TemplateException.java:168)
[ERROR]                 at io.quarkus.qute.deployment.QuteProcessor.processTemplateErrors(QuteProcessor.java:198)
[ERROR]                 ... 11 more
tmulle commented 2 years ago

I managed a workaround by creating a Template extension which simply reverses the boolean value.

This works:

{#text name="name" value=orgForm.name label=i18n:['label.orgName'] placeholder="Org Name"
            label_class="control-label form-label f-required"
            input_class="form-control input-sm"
            disabled=canEdit.not()
          /}

Template Extension:

import io.quarkus.qute.TemplateExtension;

@TemplateExtension
public class JavaExtensions {
    public static boolean not(boolean value) {
        return !value;
    }
}
FroMage commented 2 years ago

Yeah, this is another case of https://github.com/quarkusio/quarkus/issues/13106 I'm afraid. Please comment there to let @mkouba know that we want operators in expressions ;)

mkouba commented 1 year ago

@tmulle Stef is right that this is not possible at the moment. Your workaround is fine, but maybe negate would be a better name of the extension method... and you can skip the parentheses, i.e. use it like disabled=canEdit.negate.