casid / jte

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

Embed Content at render time in a div element with an id #269

Closed tschuehly closed 1 year ago

tschuehly commented 1 year ago

In Spring ViewComponent I render nested ViewComponents with the Content type.

A ViewComponent returns a record/data-class that implements the ViewContext Interface

@ViewComponent
class ActionViewComponent(
    val exampleService: ExampleService
) {
    data class ActionView(val itemList: MutableMap<Int, String>, val counter: Int, val person: Person) : ViewContext

    fun render() = ActionView(exampleService.itemList, counter, person)

The ViewContext interface implements the gg.jte.Content interface and overrides the writeTo function.

interface ViewContext : Content, IViewContext {
    override fun writeTo(output: TemplateOutput) {
        (jteTemplateEngine as TemplateEngine).render(
            getTemplate(this), getAttributes(this),
            output
        )
    }
}

For nested components that are rendered directly in a template I want to embed them automatically in a div that has an ID attribute to get a similiar behaviour as my thymeleaf implementation:

// ThymeleafViewComponentTagProcessor.kt
        val viewComponentBody = modelFactory.createText(
            engine.process(IViewContext.getTemplate(viewContext), webContext)
        )
        structureHandler.setAttribute("id", viewContext.javaClass.enclosingClass.simpleName.lowercase())
        structureHandler.setAttribute(ViewActionConstant.nestedViewComponentAttributeName, null)
        structureHandler.removeAttribute("view:component")
        structureHandler.setBody(viewComponentBody, true)

I would like to do this at runtime, as this needs to generate a new UUID to the ID as the component can be multiple times on the page. Is this possible somehow?

casid commented 1 year ago

That should work, for instance:

override fun writeTo(output: TemplateOutput) {
    output.writeContent("<div id=\"")
    output.writeContent(uuid.toString())
    output.writeContent("\">")
    (jteTemplateEngine as TemplateEngine).render(getTemplate(this), getAttributes(this), output)
    output.writeContent("</div>")
}
tschuehly commented 1 year ago

Thank you @casid it works nicely!