xmlet/HtmlFlow

Nesting dynamic bloc

benzen opened this issue · 3 comments

I'm trying to migrate a use made using thymleaf to a view using html flow.
In a table of user I discovered that we can't nest dynamic bloc.

.tbody()
  .dynamic(body -> {
    users.stream().forEach((user) -> {
      body
        .tr()
          .td()
                // should switch on presence of user.getImage() == null 
                // .img().attrClass("ui image avatar").attrSrc(String.format("data:image/png;base64,%s", user.getImageAsBase64())).__()

          .__()
        .__();
    });
  })

The error message is really clear

You are already in a dynamic block! Do not use dynamic() chained inside another dynamic!

Thanks for that.

I assume that there is a technical reason for this limitation. I don't question them, rather I'd like some guidance on how this kind of stuff should be address by a user of htmlflow.

Regards

Seams strange, doc state that this is possible to nest dynamic

https://htmlflow.org/features/ see the dynamic views section (would be nice to be able to link to a section and to a specific example)

Good catch! That example is outdated. Put it simply, in those cases we should use .of() nested in the dynamic(). (we have forgotten to update that example).

That is the result of release 3.0 and several optimizations https://github.com/xmlet/HtmlFlow#30-november-2018. Thus the .dynamic() gained a new perspective. To achieve better performance the HTML resulting of the templates resolution is internally cached. In truth that cache should be renamed to something like static denoting that HTML do not change between resolutions. On the other hand, the HTML resulting from dynamic() should be resolved on each render.

Whenever we call dynamic() we stop caching the HTML and when we close that dynamic block with .__() we start caching again the resulting HTML.

So, if we are inside a dynamic block and we call again dynamic it has no effect, because the outer block will be completely computed on render and that includes the inner block too. To avoid misleading we decided to throw that exception if the programmer made a wrong use of dynamic.

Yet, it is useful the chaining ability. So, fir that purpose we added a new .of() that let we chain any Java block, but without any side effect on caching. Thus, if you call of() out of a dynamic it will continue to cache. If you call of() inside a dynamic then it will not cache the resulting HTML.

Thanks,
Miguel

brbog commented

@fmcarvalho
Thanks for this response! I was abusing nested .dynamic() calls to make the code formatter produce indented code (for readability => helps avoiding bugs).

I got to work around it, but was ready to ditch HtmlFlow. Now with ".of()" I am back to enjoying it ;-).