holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.62k stars 504 forks source link

Using reactive variables with img tags in ReactiveHTML references unknown parameter or method #5352

Open ahuang11 opened 1 year ago

ahuang11 commented 1 year ago

Looping through a dict--this works with a div <div id="v-{{ loop.index0 }}">${icon_name}</div>:

from panel.reactive import ReactiveHTML
import param
import panel as pn
pn.extension()

class Test(ReactiveHTML):

    value = param.List(doc="The selected reactions.")

    options = param.Dict(default={"favorite": "heart"}, doc="""
        A key-value pair of reaction values and their corresponding tabler icon names
        found on https://tabler-icons.io.""")

    _template = """
        <div id="reactions" class="reactions">
            {% for reaction, icon_name in options.items() %}
            <div id="v-{{ loop.index0 }}">${icon_name}</div>
            {% endfor %}
        </div>
    """

test = Test()
test

But not <img id="reaction-{{ loop.index0 }}" src="https://tabler-icons.io/icons/{{ icon_name }}.svg" alt="${reaction}"></img>

from panel.reactive import ReactiveHTML
import param
import panel as pn
pn.extension()

class Test(ReactiveHTML):

    value = param.List(doc="The selected reactions.")

    options = param.Dict(default={"favorite": "heart"}, doc="""
        A key-value pair of reaction values and their corresponding tabler icon names
        found on https://tabler-icons.io.""")

    _template = """
        <div id="reactions" class="reactions">
            {% for reaction, icon_name in options.items() %}
            <img id="reaction-{{ loop.index0 }}" src="https://tabler-icons.io/icons/{{ icon_name }}.svg" alt="${reaction}"></img>
            {% endfor %}
        </div>
    """

test = Test()
test

Traceback:

File 'reactive.py', line 1528, in __init__:
raise ValueError( Traceback (most recent call last):
  File "/Users/ahuang/miniconda3/envs/panel/lib/python3.9/site-packages/bokeh/application/handlers/code_runner.py", line 231, in run
    exec(self._code, module.__dict__)
  File "/Users/ahuang/repos/sketches/test.py", line 6, in <module>
    class Test(ReactiveHTML):
  File "/Users/ahuang/repos/panel/panel/reactive.py", line 1528, in __init__
    raise ValueError(
ValueError: Test._template references unknown parameter or method 'icon_name', similar parameters and methods include ['_extension_name', '_rename', 'name'].
ahuang11 commented 1 year ago

As a work around, use param.depends to rebuild the HTML:

from panel.reactive import ReactiveHTML
import param
import panel as pn

pn.extension()

class Test(ReactiveHTML):
    value = param.List(doc="The selected reactions.")

    options = param.Dict(
        default={"favorite": "heart"},
        doc="""
        A key-value pair of reaction values and their corresponding tabler icon names
        found on https://tabler-icons.io.""",
    )

    _icons_html = param.String()

    _template = """
        <div id="reactions" class="reactions">
        ${_icons_html}
        </div>
    """

    @param.depends("options", watch=True, on_init=True)
    def _update_icons_html(self):
        self._icons_html = "\n".join(
            f"""
            <img id="reaction-{reaction}"
                src="https://tabler-icons.io/static/tabler-icons/icons/{icon_name}.svg"
                alt="{reaction}">
            </img>
            """
            for reaction, icon_name in self.options.items()
        )

test = Test()
test
ahuang11 commented 1 year ago

However, the workaround cannot attach scripts~