I am trying to figure out if there is a way to get...
# fritz2
j
I am trying to figure out if there is a way to get the html code of a RenderContext extension function as string, instead of using it within the render context? I am using leaflet and this would be very handy to be able to write html in kotlin, even when there is plain html code as string required, e.g. for the leaflet div icons or tooltips.
j
Hi, I take a quick look at the docs form leaflet and their API says, that you can provide a
HTMLElement
e.g. to their
divIcon
function. Did you try something similar to this?
Copy code
// simulate external leaflet API
object L {
    fun <E: HTMLElement> divIcon(element: E) {
        // here leaflet can do everything with the given HTMLElement
        // e.g. appending text to the given HTMLElement
        element.appendChild(document.createTextNode("Hello World!"))
    }
}

// small wrapper Component to support fritz2 HTML DSL
fun RenderContext.divIcon(content: RenderContext.() -> Unit) {
    L.divIcon(div {
       content()
    }.domNode)
}

fun main() {
    // calling the wrapped leaflet component 
    // and using a fritz2 component inside
    render {
        divIcon {
            icon { fromTheme { fritz2 } }
        }
    }
}
In fritz2 all our standard HTML elements e.g.
div()
have the property
domNode
which gives you the corresponding native
HTMLElement
which external libraries like leaflet can use. I hope I get your right and my approach work for you. If not please let me know 😉
j
Thanks a lot. I will try that out. :)
Tried to make it work, but unfortunately it is not quite what I was looking for. At least from my understanding. I don't want to call the leaflet divIcon function in the RenderContext, but I want to pass a function that uses the fritz2 DSL to the leaflet divIcon() JS function. Therefore, I would like to convert a function like this:
Copy code
fun RenderContext.test(){
    icon { fromTheme { fritz2 } }
}
to a HTMLElement, so that I can use it in the leaflet context like this:
Copy code
L.marker(...).setIcon( L.divIcon( test() ) )
I created a kotlin data class for the leaflet DivIcon to be able to easily handle all the icon options dynamically in my webapp and then I create a JS object out of it to display it with leaflet. Currently my data class has a string containing the html code and this would be nice to change to HTMLElement and use a fritz2 DSL there. I dont know if I am making it overcomplicated, but that is my current setup to deal with the kotlin <-> JS handover.
j
Ok, now I get you. Currently you can try this approach:
Copy code
fun RenderContext.stringify(content: RenderContext.() -> Unit): String {
    return Div(job = this.job).apply {
        content()
    }.domNode.innerHTML
}

fun main() {
    render {
        pre {
            +stringify {
               icon { fromTheme { fritz2 } }
            }
        }
    }
}
You need to create a wrapper function (like
test()
). You can then use the fritz2 components functions inside the
content
parameter. Internally a
Div()
gets created to get access to the underlying
domNode
and
innerHTML
which presents the HTML generated by the fritz2 component (here
icon()
). I hope that helps 😉
j
Thanks a lot! This works great. I changed it a bit and ended up using:
Copy code
fun stringify(content: RenderContext.() -> Unit): String {
    return Div(job = Job(parent = null)).apply {
        content()
    }.domNode.innerHTML
}
This allows me to use the string everywhere, also outside the RenderContext. 🙂 Does that make sense or is it not ideal to define the job like this without parent?
j
Yes, I thougt about it, but I think if you don't face troubles, it should work well to create a new
Job()
everytime you call
stringify()
function. Instead of a
String
you can also use the
domNode
directly. This should be more performant ;)
j
Indeed, I mentioned some performance issues with a bigger amout of markers I am creating with this. I thought it relates to the svg icons I am using instead of icon-font icons, but this could be related to the amount of Job() creations... I will try to use the domnode and maybe figure something out to handover an existing job, instead of creating a new one.