Hi,
I’m trying to add custom HTML+JS elements to Panel, and I can’t seem to do it. Moreover, slightly different approaches result in seemingly random behavior, so if anyone could explain what happens in the client side, mostly, it’d be wonderful (I didn’t manage to follow the call-tree to the client side).
1. The simplest attempt - the constant string
class TestElement(pn.reactive.ReactiveHTML):
_template = """
<script type="text/javascript">
function on_click() {
alert('clicked');
}
</script>
<div id="root">
<input type="button" value="Click Me" onclick="on_click();" />
</div>
"""
TestElement().show()
Result: Fails! Both script and input elements appear in the browser, but the event in the DOM is different and fails.
2. Constant script & variable HTML
class TestElement(pn.reactive.ReactiveHTML):
src = param.String(doc="HTML source code", default='<input type="button" value="Click Me" onclick="on_click();" />')
_template = """
<div id="root">
<script type="text/javascript">
function on_click() {
alert('clicked');
}
</script>
${src}
</div>
"""
TestElement().show()
Result: Seemingly works! But the script tag is not there
HOWEVER, when I set the parameter with the exact same value as the default parameter
TestElement(src='<input type="button" value="Click Me" onclick="on_click();" />').show()
I get:
ValueError: String parameter ‘src’ only takes a string value, not value of type <class ‘panel.pane.markup.Markdown’>.
When I set
class TestElement(pn.reactive.ReactiveHTML):
# ...
_child_config = {
'src': 'literal',
}
The site opens successfully, but the script
tag isn’t there and it and, unlike before, the function is also not declared in the memory (at least in the window scope):
3. Variable script & variable HTML
class TestElement(pn.reactive.ReactiveHTML):
src = param.String(doc="HTML source code", default='<input type="button" value="Click Me" onclick="on_click();" />')
script = param.String(default="function on_click() { alert('clicked'); }", doc="Scripts to be executed")
_template = """
<div id="root">
<script type="text/javascript">
${script}
</script>
${src}
</div>
"""
Result: Works with default values! Fails without.
However, if I set the both the parameter’s _child_config
to 'literal'
as suggested by the documentation, it doesn’t work (the function is not defined when called). The weird thing is that has to do with setting src
as 'literal'
and not script
(checked by changing any to 'model'
).
4. Variable script & variable HTML - set dynamically
class EmbeddedHTMLPart(BootstrapReactiveHTML):
src = param.String(default="", doc="HTML source code")
script = param.String(default="", doc="Scripts to be executed")
_child_config = {
'script': 'literal',
}
_template = """
<div id="root">
<script type="text/javascript" id="script">
${script}
</script>
<div id="placeholder">123123123</div>
</div>
"""
_scripts = {
'render': """
text = document.createElement('textarea');
text.innerHTML = data.src;
$(placeholder).html(text.value);
"""
}
Result: Works! but that’s the only way it does, and it’s hacky as hell.
Finally
To summarize, some of the above behaviors are bugs (like the difference between default and set value), some are strange behaviors (like turning stuff into Markdown
without asking).
Any explanations of these behaviors would be welcome. Also, explaining which one is the correct way to achieve inserting a custom HTML with an accompanying script is.
Sidenotes:
- There were other trials that I can not recall all of them, but again - small changes result in large deviations in behavior, and that’s very hard to work with - especially considering the lack documentation.
- I wish to say that the project seems great with a lot of potential, but it is largely undocumented (especially core concepts, descriptions of the inheritance tree, and what happens in the client side), and that’s a shame because with the proper documentation, I believe that one could do wonderful customizations and contribute to the project.