TemplateGlobal variables/methods are not available in Qute tags
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?
@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
/cc @mkouba (qute)
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.
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 /}
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.
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.