Next question. Hopefully somebody can answer all i...
# kotlinx-html
r
Next question. Hopefully somebody can answer all in a batch 🙂 I'm starting to build components (rather than Flowcontent extension functions) for some cases; e.g. I can make:
Copy code
class Column(heading: String, consumer : TagConsumer<*>): DIV(mapOf(), consumer) {
    init {
        h1 {
            +heading
        }
    }
}
and then within the dsl call it as:
Copy code
appendHTML().div("p-4") {
                ...
                Column("Column 1", consumer)
                Column("Column 2", consumer)
                Column("Column 3", consumer)
                Column("Column 4", consumer)
                Column("Column 5", consumer)
this is pretty nice, because now I can create components in a typesafe way. what I don't like is having to explicitly pass in consumer. is there a better pattern for this?
this gets clunkier when you pass components to each other:
Copy code
Board("My Board",
                    listOf(Column("Column 1", consumer),
                           Column("Column 2", consumer),
                           Column("Column 3", consumer),
                           Column("Column 4", consumer),
                           Column("Column 5", consumer)), consumer)
and this isn't quite right (the columns render before the h1 in this case, though i'm sure i'll figure this out, eventually):
Copy code
class Board(heading: String, columns: List<Column>, consumer : TagConsumer<*>): DIV(mapOf(), consumer) {

    init {
        h1 {
            +heading
        }
        div {
            columns.forEach {
                it.visit {  }
            }
        }
    }
}
e
Hey @Reuben Firmin, it looks like all components needs to be wrapped in a single tag in the init block. Could you please check it?
r
I've been working on this today, and just hit on one approach. I don't know if recommended, but e.g.:
Copy code
class Board(val heading: String, consumer: TagConsumer<*>): DIV(mapOf(), consumer) {

    fun render() {
        h1 {
            +this@Board.heading
        }
    }
}

fun FlowContent.board(heading: String, block : Board.() -> Unit = {})
        = Board(heading, consumer).visit {
            render()
            block()
        }
Copy code
class Column(val heading: String, consumer : TagConsumer<*>): DIV(mapOf(), consumer) {

    fun render() {
        h1 {
            +this@Column.heading
        }
    }

    companion object {
        inline fun Board.column(heading: String, crossinline block : Column.() -> Unit = {}) : Unit
        = Column(heading, consumer).visit {
            render()
            block()
        }
    }
}
This does the right thing and lets me do this:
Copy code
board("My Board") {
                    column("Column 1")
                    column("Column 2")
                    column("Column 3")
                    column("Column 4")
                    column("Column 5")
                }
...but I'm not 100% sure if that's what was intended (the docs on github don't cover this); also not sure if this'll scale to more complex components. (my issue with the inits above was that Column(s) got instantiated before Board and so rendered first, because their inits rendered first)
e
Yep, and it looks like rending inside init is not a good idea