To build reusable components, I end up using a mix of a lot of extension functions and Kotlin's function pointer syntax.
So, the components themselves will look something like this:
fun HtmlBlockTag.radioButtonWithLabel(
groupName: String,
id: String,
hidden: Boolean = false,
radioButtonFunc: (INPUT.() -> Unit)? = null,
func: LABEL.() -> Unit
) {
radioInput(name=groupName) {
this.id = id
this.hidden = hidden
radioButtonFunc?.invoke(this)
}
label { this.htmlFor = id; func() }
}
And then use of them will be like this: call.respondHtml {
body {
div(CSS_CLASS_NAME) {
radioButtonWIthLabel(MORE_CSS_CLASS_NAME, "group", "id") {
+"Text for the label"
}
}
}
}
More complicated examples just extend that quite a lot.I've also got whole files dedicated to single extension functions that end up being a whole section that I can place anywhere.
---
And then to test those single-function components, I'll do something like this:
class SingleSectionTest {
private suspend fun ApplicationTestBuilder.buildApplicationAndCall(
data: DataUsedForSection
): Document {
application {
routing {
get("test") {
call.respondHtml {
body {
renderSingleSection(data)
}
}
}
}
}
val response = client.get("test")
val body = Jsoup.parse(response.bodyAsText())
return body;
}
@Test
fun `simple test case`() = testApplication {
val data = DataUsedForSection("a", "b", "c")
val body = buildApplicationAndCall(data)
// all the asserts
}
}
And so on. Is this what you were wondering? Or would you like a different sort of example?
That's pretty much what I was looking for, thank you for sharing! I think that's probably the nicest way I've seen to do it, annoying that Kotlin seems to force you to add it as a child (? idk the word...) of an existing HTML tag, wish you could just import a component or something :(