Nested custom tags/attributes

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Nested custom tags/attributes

Thibault Duchateau
This post was updated on .
Hi !

I'm trying to develop a dialect for custom tags/attributes that generate HTML tags. Those generated tags could have a body composed of native HTML tags or others custom tags/attributes that also need to be processed by Thymeleaf.

Example :

<customTag attr1="...">
   <table dt:attr2="...">
      ...
   </table
</customTag>

with <customTag> and attr1 processed by Dialect1 (which generates HTML tags, in order to wrap the table) and dt:attr2 processed by Dialect2.

But as nodes are executed in order, Dialect1 and its processors are well executed but not Dialect2 ones, even using the existing flags.

So, is there any workaround like :
* a way to process nodes more than once ?
* a kind of dialect precedence which would indicate Thymeleaf to process all processors of a dialect before/after those of another one ?
* maybe another one ? :-)

Thanks !

Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

Emanuel
Administrator
Is your example missing a few things?  I can't see the dt:attr2 you mentioned which didn't get processed.
Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

Thibault Duchateau
Sorry :-/

Post edited !
Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

Emanuel
Administrator
In reply to this post by Thibault Duchateau
I've never made a custom tag/element, so am not sure if there's anything special you need to do to make sure inner content gets processed.  I'm curious so I'll take a look at those too.

To answer your other questions:

 - There are these flags, recomputeProcessorsAfterEachExecution and recomputeProcessorsImmediately on the Node class which I think can be altered to get Thymeleaf to look at the element/tag again to see if there's anything more it needs to do.  I haven't had much luck with those myself when I was trying to get Thymeleaf to reprocess a node (I probably don't understand them fully), but I think something changed with them in one of the recent releases, so maybe it does 'work' now - I haven't tested.

 - There isn't a 'process this dialect before all others' precedence, just the 'run this processor before all other processors on this node' precedence which you've probably seen and had to implement.


Question: are any standard Thymeleaf processors within your <customTag> getting run?  (This might tell you if the problem is in your first dialect, or just the second one)
Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

Thibault Duchateau
Thanks Emanuel !

Actually, it would be great to be able to "recomputeProcessorsImmediately" either on the whole current template or on a specific node's inner content.
Well, I'll take a closer look at those flags and how they work. Thanks !

Good idea for the standard dialect. Unfortunately, still the same exception :

org.thymeleaf.exceptions.TemplateProcessingException: Error processing template: dialect prefix "th" is set as non-lenient but attribute "th:text" has not been removed during process (plugins/scroller:42)
Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

Emanuel
Administrator
I was suspicious of whether Thymeleaf was processing anything inside a custom element, but I just did some tests and was able to get inner content processed.  (I just added a 'test1' element processor and 'test2' attribute processor to an existing dialect, then put standard th processors in it, instead of making a second dialect.)

I has this in a page:

<layout:test1 layout:test2="">
  <p th:text="'Testing stuff'">Stuff</p>
</layout:test1>

The element processor added an inner paragraph element with the text 'Test1':

Element paragraph = new Element("p");
paragraph.addChild(new Text("Test1"));
element.addChild(paragraph);

return ProcessorResult.OK;

The attribute processor added an inner paragraph element with the text 'Test2', then removed itself:

Element paragraph = new Element("p");
paragraph.addChild(new Text("Test2"));
element.addChild(paragraph);
element.removeAttribute(attributeName);

return ProcessorResult.OK;

But I managed to get the desired result in the final page without an exception.  The Thymeleaf th:text seemed to get processed too (I was afraid leaving the <layout:test> element would throw an exception, but it didn't seem to):

<layout:test1>
  <p>Testing stuff</p>
<p>Test1</p><p>Test2</p></layout:test1>

Would you be able to share the code of the dialects you're writing?
Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

Thibault Duchateau
This post was updated on .
Hmmm .. I must be trying to do something's special ... :-)

Actually, I'm making a demo of the DataTables4j dialect. This is a typical use case where lots of code have to be repeated in plenty of pages.

For each DataTables4j example, I use the Bootstrap "Nav" component to display the needed code in a tab and the result in another tab.

The goal is to let Thymeleaf generate all the HTML code that is surrounding the table tag below :

<ul class="nav nav-tabs">
   <li class="active"><a href="#tabDemo" data-toggle="tab">Demo</a></li>
   <li><a href="#tabCode" data-toggle="tab">Code</a></li>
</ul>
<div class="tab-content">
   <div class="tab-pane active" id="tabDemo">
      <table id="myTable" dt:table="true">
         <thead>
            <tr>
               <th>Id</th>
               <th>Firstname</th>
               <th>Lastname</th>
               <th>Street</th>
               <th>Mail</th>
            </tr>
         </thead>
         <tbody th:remove="all-but-first">
            <tr th:each="person : ${persons}">
               <td th:text="${person.id}">1</td>
               <td th:text="${person.firstName}">John</td>
               <td th:text="${person.lastName}">Doe</td>
               <td th:text="${person.address.street1}">Nobody knows !</td>
               <td th:text="${person.mail}">john@doe.com</td>
            </tr>
         </tbody>
      </table>

   </div>
   <div class="tab-pane" id="tabCode">
      <pre id="code" class="prettyprint linenums">
         <!-- I'd like to have here the code present in the first tab, but as text and pretty printed -->
      </pre>
   </div>
</div>

What I'm trying to do is the following custom tag :

<bootstrap type="tabs" nature="code">
   <tab name="Demo" active="true">
      <table id="myTable" dt:table="true">
         <thead dt:scroller="true">
            <tr>
               <th>Id</th>
               <th>Firstname</th>
               <th>Lastname</th>
               <th>Street</th>
               <th>Mail</th>
            </tr>
         </thead>
         <tbody th:remove="all-but-first">
            <tr th:each="person : ${persons}">
               <td th:text="${person.id}">1</td>
               <td th:text="${person.firstName}">John</td>
               <td th:text="${person.lastName}">Doe</td>
               <td th:text="${person.address.street1}">Nobody knows !</td>
               <td th:text="${person.mail}">john@doe.com</td>
            </tr>
         </tbody>
      </table>
   </tab>
</bootstrap>

So, I have two dialect : one for the boostrap tag, and another for DataTables4j (element and attribute processors that process the table tag).

For now, I just tried, in the Bootstrap tag processor, to get all the children of the bootstrap tag (tab element and its content) and copy them as is, in the generated HTML code needed by Bootstrap (ul, li, ...). This is maybe what I'm doing wrong.

I soon as I can, I'll post some code but for now, this is too ugly ! :-)
Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

danielfernandez
Administrator

Hi

Just a point -- setting "recomputeProcessorImmediately(true)" on a still-non-processed node should make thymeleaf process it even if you have added thymeleaf-processable attributes to it.

Note this only applies to "non-processed" nodes, because (currently) only one iteration of processing is performed on the DOM tree.

Regards,
Daniel.

Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

Thibault Duchateau
Hi !

Shame on me !

I was really making an incorrect use of "recomputeProcessorImmediately(true)" because I wanted other processors (from other dialect) to be computed, not the current one being recomputed !

So, first I didn't need "recomputeProcessorImmediately(true)" but actually "setProcessable(true)" !
Now it works like a charm !

For information, I had to iterate over all the children of the previous "tab" tag to make it work :

for(Node node : <children_of_the_tab_tag>){
	node.setProcessable(true);
}

Emanuel & Daniel, many thanks !
Reply | Threaded
Open this post in threaded view
|

Re: Nested custom tags/attributes

Thibault Duchateau
Hi again

I just pushed the code !
Feel free to take a look !