xmlet/HtmlFlow

View with dynamic and static attribute / Placement of dynamic() block

shimikano opened this issue · 6 comments

The following test creates a view, adds an attribute to a div() in a dynamic() block, and then adds a static attribute.

  @Test
  public void dynamicAttribute() {
    var view = HtmlFlow.view(page -> {
      page
        .div()
          .<String>dynamic((div, model) ->
            div.addAttr("dynamic-attribute", model)
          )
          .addAttr("static-attribute", "world")
        .__();
    });

    var actual = view.render("hello");

    var expected = """
      <div dynamic-attribute="hello" static-attribute="world">
      </div>""";

    assertEquals(expected, actual);
  }

The rendered string is:

<div dynamic-attribute="hello">
static-attribute="world"
</div>

As opposed to the expected:

<div dynamic-attribute="hello" static-attribute="world">
</div>

If I move the static-attribute line into the dynamic() block, the test passes.

So I wonder if this is a bug or if dynamic() is not supposed to be used like this.

Using HtmlFlow 4.1.

That is an issue that we were not able to solve.

In that kind of HtmlFlow view we are evaluating the static blocks before-hand without running the continuations of dynamic blocks. Thus, we have no way to know whether a dynamic block is closing (i.e. <div>) or leaving the tag opened (i.e. <div). We had to take a decision, and we assumed that is better to presume that a dynamic block always kept the tags closed.

That’s the reason of that behavior observed on your test.

Since, we do not have immediate solution for this we suggest that you move your static attribute into the dynamic block as you proposed in your work-around.

There will not be any significant overhead of processing a further attribute in dynamic.

Thank you

Dear Fernando

I understand, thank you very much for your swift reply and explanation.

Best regards

Sure thing, I'm happy to do so.

Off-topic, but I'm experimenting with HtmlFlow as a replacement for Thymeleaf. So far I'm happy with the reduced complexity and not having to deal with limitations of the external Thymeleaf DSL. For example, adding the CSRF token to the view? - Just do it yourself in Java (or Kotlin) instead of having to rely on Thymeleaf-provided magic (${_csrf.token}). This is quite liberating. The better performance is also a big plus, of course.

Disadvantages are the poorer readability compared to HTML-like templates, the inability to easily copy-paste existing HTML into your templates (sure, Flowifier may help, but it's an extra step), and the poor formatting/indenting support of IDEs (cf. #91). For the latter, Kotlin extension functions help BTW.

I'll report on further findings later on.

I have developed a rudimentary plugin that serves its purpose, but it hasn't been submitted to the IntelliJ Marketplace. You'll need to manually install the plugin JAR file. I hope it proves useful to everyone.
@shimikano
https://github.com/changchengqin/indent-folder

Thank you @changchengqin.

I'm using Kotlin extension functions to create a mini DSL with proper scoping using the language-level blocks ({ and }), e.g.:

htmlFlowDoc {
  table {
    thead {
      tr {
        th { t("Sample th 1") }
        th { t("Sample th 2") }
      }
    }
    tbody {
      tr {
        td { t("Sample td 1") }
        td { t("Sample td 2") }
      }
    }
  }
}

This has helped a lot when authoring HtmlFlow templates.

Just to let you know that we have just released HtmlFlow 4.6 with full compatible API for Kotlin builder with function literals with receivers that are fully compatible with the already exiting Java API. In truth you can mixed both.

All examples are updated here https://htmlflow.org/features and snippets include a tab for Kotlin. Now you can write as bellow:

System.out.doc {
  html {
    head {
      title { text("HtmlFlow") }
    }
    body  {
      div {
        attrClass("container")
        h1 { text("My first HtmlFlow page") }
        img { attrSrc("http://bit.ly/2MoHwrU") }
        p { text("Typesafe is awesome! :-)") }
      }
    }// body
  } //html
} // doc