quarkus icon indicating copy to clipboard operation
quarkus copied to clipboard

TemplateGlobal variables/methods are not available in Qute tags

Open gbourant opened this issue 6 months ago • 5 comments

Describe the bug

The template global variable YEAR is not available in Qute tag input. If you call the hello endpoint it throws Caused by: io.quarkus.qute.TemplateException: Rendering error in template [tags/input] line 1: Key "YEAR" not found in the map with keys [_args] in expression {YEAR} but if you call the year endpoint it returns the current year.

If we use {#input _isolated=false/} it will work.

Shouldn't TemplateGlobals be available even in Qute tags?

Reprocuder

@TemplateGlobal
public class GlobalVar {
    public static final int YEAR = Year.now().getValue();
}

@Path("")
public class HelloResource extends Controller {

    @Inject
    Engine engine;

    @GET
    @Path("hello")
    public TemplateInstance hello() {
        return engine.parse("{#input /}").instance();
    }

    @GET
    @Path("year")
    public TemplateInstance year() {
        return engine.parse("{YEAR}").instance();
    }

}

templates/tags/input.html

YEAR:{YEAR}

Expected behavior

No response

Actual behavior

No response

How to Reproduce?

No response

Output of uname -a or ver

No response

Output of java -version

No response

Quarkus version or git rev

No response

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

No response

gbourant avatar Jun 12 '25 17:06 gbourant

/cc @mkouba (qute)

quarkus-bot[bot] avatar Jun 12 '25 17:06 quarkus-bot[bot]

So if you look at the docs, you can read that Global variables are added as computed data of any TemplateInstance during initialization. In other words, for each global variable the TemplateInstance#computedData() method is called in a TemplateInstance.Initializer. Now given the fact that user tags are isolated by default, i.e. cannot reference the data from the parent context, the described behavior is expected.

The good thing is that you can always use the global: namespace to access global variables. In your case, it would be {global:YEAR}.

I'm not quite sure whether it would make sense to try to change the behavior now.

mkouba avatar Jun 12 '25 18:06 mkouba

I had tried the global namespace but I did not change it to to all occurrences so I was still getting the same error but on different line 🤦🏻‍♂️. Yeah, it works.

Also I have updated the reproducer with an another example. When a Qute tag uses a normal template, it still encapsulates the global variables. (It works with the global namespace).

If I just render the root.html it works as expected. If I render the onboardingForm.html which uses the root.html, I get io.quarkus.qute.TemplateException: Rendering error in template [root.html] line 1: Key "YEAR" not found in the map with keys [_args] in expression {YEAR}. I think that this behavior looks inconsistent.

onboardingForm.html

{#include root.html}
    >Text from onboardingForm.html<
{/include}

root.html

Current Year:{YEAR}
{#insert /}

gbourant avatar Jun 12 '25 20:06 gbourant

I don't think it's inconsistent. It may not seem intuitive but if you look at the template hierarchy there's the top-level template which calls a user tag by means of {#onboardingForm /}. As we mentioned above the user tags are isolated by default, i.e. they can't see the parent context. So anything inside the tag, including the included root.html, cannot see the context of the top-level template, including global variables.

I know that it sounds weird that global variables are not always accessible but I'd recommend to stick with the global: namespace because it also describes where the value comes from.

mkouba avatar Jun 13 '25 06:06 mkouba

It's ain't a big deal, since it throws an error. I might add a test later/next week to check that the error is always thrown.

gbourant avatar Jun 13 '25 06:06 gbourant