casid / jte

Secure and speedy templates for Java and Kotlin.
https://jte.gg
Apache License 2.0
830 stars 62 forks source link

[Question] Rendering parts/fragments of the page #213

Closed maxwellt closed 1 year ago

maxwellt commented 1 year ago

In Thymeleaf it's possible to render a part of a template using the syntax " :: ". Do you think this is something that would be possible in JTE?

The "obvious" solution to this is to simply extract the fragment into its own JTE template, but that can oftentimes lead to an explosion of template files.

In my mind the ideal solution would be that you can mark a part of a JTE template as a fragment which, when the template is compiled into a Java class, is itself compiled into its own Java class (so one Java class for the template as a whole and another for the fragment). The fragment Java class would then be included/called from the parent Java class. This way the fragment Java class can perhaps be called on its own, to only render that part?

No idea if this is feasible but a use case where this is very handy is when using something like HTMX. A Javascript framework that allows any HTML element to perform HTTP actions and handle the returned HTML. This HTML is often a smaller part of the page the user is on (i.e. the fragment I described above). An easy example is, you have a form to enter a "To Do" item, below it you have a list of your already entered items. Adding a new "To Do" item causes the backend to only send back the HTML of the list (the fragment) which is then inserted in the page.

casid commented 1 year ago

It was a design decision for jte, that every template lives in its own file. I've seen the opposite far too often, god macro templates that become very hard to maintain.

Yes, HTMX is awesome! Your example would work very well with two template files.

todo/list.jte

@param Model model

<ul>
@for(var item : model.items)
   @template.todo.item(item = item)
@endfor
</ul>

todo/item.jte

@param Item item

<li>${item.checked}: ${item.name}</li>

This results in rather small template files that do one thing. With the IntelliJ plugin it's very comfortable to navigate around. For version control systems with many developers working on the system, having smaller files also avoids merge conflicts.

maxwellt commented 1 year ago

Thanks for the feedback @casid, I certainly agree that it has its advantages as well, but sometimes it is nice to be able to mark some part of a template as its own fragment.

Alternatively I see that HTMX also has the ability to select a specifc part of a returned template to swap (hx-select), this might be useful in some cases where a separate template is not wanted.

casid commented 1 year ago

For HTMX you would still need two endpoints, no?

Something like: todo/list.htm todo/item.htm?id=1

public Response todoList() {
   return render("todo/list.jte", loadTodos());
}
public Response todoItem(long id) {
   return render("todo/item.jte", loadTodoItem(id));
}

I don't see the advantage of calling into the same template file.

maxwellt commented 1 year ago

Not necessarily, but I might be confusing you by my "constraint" of not wanting to create a separate template for everything.

In the example you provided of a ToDo list you could work with a single todo.jte template and simply extract (hx-select) the <ul> element out of it when you wish to only rerender the list of items.

<input type="text" hx-post="/items" hx-trigger="blur" hx-select="#item-list" hx-target="#item-list">

<ul id="item-list">
    <li>item 1</li>
    <li>item 2</li>
</ul>

I've just typed this from memory, no idea if it would actually work. Just wanted to show that the /items end point could simply return the whole todo.jte template and then use hx-select to only pick the #item-list and swap it. Not saying this is the best use case, but it would allow for my original use case if you don't want to create a new template for everything.

casid commented 1 year ago

Ah, I see, thanks for the clarification!

checketts commented 7 months ago

@maxwellt Were you able to successfully leverage multiple template files? I'm migrating a project from Thymeleaf that also uses HTMX and fragments.

Inline fragments have been incredibly useful for our cases since HTMX just re-renders that part of the page. So I'm having trouble letting it go...

I'm interested in any orgainizational/naming tips, etc that you may have leveraged

checketts commented 7 months ago

I stand corrected. @casid was right that the plugin integration and jumping between files makes this not nearly as painful as I was worried about. Sorry for causing noise on an old discusion.

To ease my Thymeleaf to JTE migration I just extracted the fragments into similarly named files (demo.html -> demo.kte, demo-frag1.kte) The rest was quite straight forward!

maxwellt commented 7 months ago

@checketts indeed, I've also simply used separate files and it works fine