thymeleaf / thymeleaf

Thymeleaf is a modern server-side Java template engine for both web and standalone environments.
http://www.thymeleaf.org
Apache License 2.0
2.78k stars 501 forks source link

Standard th: attributes not executing on nested custom tag #848

Open xtianus opened 2 years ago

xtianus commented 2 years ago

I'm trying to write a custom tag with nested custom tags. Something like

<my:out th:if="true">
    <my:inside th:text="realtext">dummy</my:inside>
</my:out>

The th:if attribute on the my:out tag works fine but the th:text attribute is ignored on the my:inside tag. Actually any th attribute is ignored in the inside tag.

I'm using a custom AbstractElementModelProcessor that iterates over the IModel elements.

My guess is that tags inside custom tags are not processed when the standard dialect runs. How can I fix this?

SO question here

trinhnx commented 2 years ago

@xtianus could you give me some samples to look up?

xtianus commented 2 years ago

@trinhnx you can see an example implementation in the YadaInputTagProcessor class here. That's not a simple example though. I don't have a test that you can easily run.

xtianus commented 2 years ago

I made some experiments with a simple use case.

Given this HTML

<yada:test>
    <p th:if="true" th:text="ciao1">hello1</p>
    <yada:testInside th:if="true" th:text="Apples1">Inside1</yada:testInside>
</yada:test>
<yada:test>
    <p th:if="false">hello2</p>
    <yada:testInside th:if="false">Inside2</yada:testInside>
</yada:test>

and this processor implementation

public class TestTagProcessor extends AbstractElementModelProcessor {

    public TestTagProcessor(String dialectPrefix) {
        super(TemplateMode.HTML, dialectPrefix, "test", true, null, false, 12000); 
    }

    @Override
    protected void doProcess(ITemplateContext context, IModel model, IElementModelStructureHandler structureHandler) {
        System.out.println("---");
        for (int i = 0; i < model.size(); i++) {
            ITemplateEvent iTemplateEvent = model.get(i);
            if (iTemplateEvent instanceof IOpenElementTag) {
                final IOpenElementTag openTag = (IOpenElementTag) iTemplateEvent;
                System.out.println("openTag: " + openTag.getElementCompleteName());
            } else {
                System.out.println("node: " + iTemplateEvent.toString().trim());
            }
        }
    }
}

I get this output in the page

ciao1

Apples1

and this console output

---
openTag: yada:test
node: 
openTag: p
node: hello1
node: </p>
node: 
openTag: yada:testInside
node: Inside1
node: </yada:testInside>
node: 
node: </yada:test>
---
openTag: yada:test
node: 
openTag: p
node: hello2
node: </p>
node: 
openTag: yada:testInside
node: Inside2
node: </yada:testInside>
node: 
node: </yada:test>

so I deduce that the th: attributes are being processed, but on a "different level" than the custom tag. In other words, th:if and th:text give the desired result, but the custom tag doesn't know about them.

I was expecting that th:if="false" would prevent the custom tag processor from seeing the node at all, but the console log shows that the node is processed as if th:if didn't exist. I tried with different PROCESSOR_PRECEDENCE values and nothing changes. Also the text content of the nodes is not changed by th:text.

How do I fix this?