Open benjamin-dreux opened 5 days ago
dynamic
method is available only in HtmlView
. HtmlView
maintain an internal cache of static HTML blocks. HtmlView
and HtmlDoc
inherit from HtmlPage
, but the latter does not perform pre-encoding or maintain an internal cache.In terms of functionality, HtmlView
and HtmlDoc
offer the same features. You can build identical views, fragments, partials, or layouts with either approach. The main difference lies in the pre-encoding performed by HtmlView
. For this reason, all examples at htmlflow.org/features include side-by-side comparisons of both approaches.
On the other hand, HtmlDoc
has fewer requirements, as it can be used in a chainable manner with the of()
scope method. Due to the internal caching mechanism, using partials or fragments with HtmlView
comes with certain constraints. To address this, there is a dedicated section about the use of HtmlView
and fragments: Layout and Partial Views (Fragments).
In contrast, fragments used with HtmlDoc
do not have these issues.
That's precisely the documentation with which I'm still unsure if I'm dooing the right thing.
In the exemple I provided, yes I'm using of
builder to include a other block, but since the second block include a dynamic block, I assume that there is no performance penalty.
Given my basic testing it seems I get it correctly. If so, what I would like to see / propose is a more basic explanation of how to compose function call in order to build a view from the tinyest function up to a complete page.
I what to state loud and clear that If i'm using html flow the right way on this, I was after that kind of composition for a LOOOOONG time. In fact since I've toyed for the first time with react back in 2013, but in a java template environement.
Have you already checked out https://github.com/xmlet/spring-petclinic?
I was expecting that the sample implementation of the Spring Petclinic using HtmlFlow would provide enough examples for most use cases when building a web app in Spring MVC with HtmlFlow, specifically regarding layouts, fragments, data binding, and similar features.
dynamic
When you stated: "since the second block includes a dynamic block, I assume there is no performance penalty." — this statement is not entirely accurate. The concern here is not performance, but caching.
The purpose of dynamic
is to prevent HtmlView
from caching the dynamic parts of a web template. Since the output of these parts depends on the provided model, you cannot reuse the resulting HTML for subsequent renderings. Additionally, dynamic
grants access to the model
instance.
Your example is correct, but to better understand the role of dynamic
, consider an alternative approach to achieve the same output in your example.
Imagine modifying your template
function by moving the .of(ContactEditView::hiddenInputId)
call into the previous dynamic
block, like this:
.<ContactEditModel>dynamic((form, model) -> form
.attrAction(format("/contacts/%s/update", model.id()))
.of(ContactEditView::hiddenInputId)
)
This will compile without errors but result in a runtime exception:
IllegalStateException: You are already in a dynamic block! Do not use dynamic() chained inside another dynamic!
This occurs because the hiddenInputId
also has a dynamic block and is being called from within other dynamic scope. Nested dynamic scopes are not allowed.
In this scenario, you don’t need to use dynamic
or of
at all. You can simply adjust the hiddenInputId
function to accept the model as an argument:
static void hiddenInputId(Form<?> parent, ContactEditModel model) {
parent
.input()
.attrType(EnumTypeInputType.HIDDEN)
.attrName("id")
.attrValue("%s".formatted(model.id()))
.__();
}
Then, in the template
function, use it like this:
.<ContactEditModel>dynamic((form, model) -> form
.attrAction(format("/contacts/%s/update", model.id()))
.of(__ -> hiddenInputId(form, model))
)
Both solutions are correct. Your original example and this alternative are equally valid. The primary difference lies in the number of static blocks managed by HtmlFlow. Your example has 3 static HTML blocks intertwined with 2 dynamic blocks, whereas my alternative proposal has 2 static HTML blocks with 1 dynamic block.
To help you better understand the rationale behind dynamic
, I’ve created a gist with some images that illustrate this concept. Check it here: https://gist.github.com/fmcarvalho/c75091698c00c55439f305efd0d923a2
Note in the 3rd image of the Gist that each dynamic block of the template turns in a BiConsumer
function that will be called later during the rendering process in HtmlFlow. After the pre-processing (i.e. pre-encoding) of a template by the HtmlFlow the dynamics disappear and are turned in continuations. These continuations are executed during rendering and cannot include additional dynamic calls. This is why nested dynamic blocks are not supported in this approach.
We’re are getting close to what I’m looking for.
Your last exemple is what I started doing at first to limit the number of dynamic blocks, mostly because I’m lazy.
but the I thought that what I really want is cache as mouche possible of my template, and keep the least possible content inside my dynamic blocks.
I didn’t conduct any performance testing on this subject. Do you know which approche is more efficient and why?
if in such a case there is a clear benefit for one or the other that’s what I would like to see more proéminent on the project’s website.
In the last few days I'm using more and more HtmlFlow.
At first i tended use dynamic bloc in the lowest place possible in the html tree.
Then I wonder what would happened if I switched to a using it the other way arround.
Now I'm back to the lowest place possible.
My reason is to be able to compose my page view more easly.
See some of my exemples
This is one of the cool thing of this library, we can compose views. What I want to discuss is, should the documentation push the user in using the dynamic block on the lower position. What I assume to be a side benefit is the fact that the cache of the view is better used with the way of using htmlFlow.