Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReactiveHTML Select example issues #5452

Open
MarcSkovMadsen opened this issue Aug 27, 2023 · 1 comment
Open

ReactiveHTML Select example issues #5452

MarcSkovMadsen opened this issue Aug 27, 2023 · 1 comment
Labels
type: bug Something isn't correct or isn't working
Milestone

Comments

@MarcSkovMadsen
Copy link
Collaborator

MarcSkovMadsen commented Aug 27, 2023

I'm on the current main branch of Panel.

The how-to documentation for ReactiveHTML contains the Select example. It has issues as you will see below.

Issues

Reference Example

This is the example from the documentation. As you can see 'A' is selected in the custom Select but not as a value. I would expect them to be synced. I would expected ReactiveHTML to make sure they are synced.

import panel as pn
import param

pn.extension()

class Select(pn.reactive.ReactiveHTML):

    options = param.List(doc="Options to choose from.")

    value = param.String(doc="Current selected option")

    _template = """
    <select id="select" value="${value}" style="width: 100%">
      {% for option in options %}
      <option id="option">${option}</option>
      {% endfor %}
    </select>
    """

    _dom_events = {'select': ['change']}

select = Select(options=['A', 'B', 'C'])
pn.Column(select, select.param.value).servable()

image

With value defined.

If I define the value the opposite happens

import panel as pn
import param

pn.extension()

class Select(pn.reactive.ReactiveHTML):

    options = param.List(doc="Options to choose from.")

    value = param.String(doc="Current selected option")

    _template = """
    <select id="select" value="${value}" style="width: 100%">
      {% for option in options %}
      <option id="option">${option}</option>
      {% endfor %}
    </select>
    """

    _dom_events = {'select': ['change']}

select = Select(value="B", options=['A', 'B', 'C'])
pn.Column(select, select.param.value).servable()

image

Additional Context

I believe the behaviour must be due to bugs. If not then we need to document how to create a proper Select. Otherwise the example is worthless.

I could not figure out how to fix this, so I believe most other users would not be able to.

@MarcSkovMadsen MarcSkovMadsen added the type: bug Something isn't correct or isn't working label Aug 27, 2023
@MarcSkovMadsen MarcSkovMadsen added this to the next milestone Aug 27, 2023
@MarcSkovMadsen MarcSkovMadsen changed the title ReactiveHTML Select example full of issues ReactiveHTML Select example issues Aug 27, 2023
@emcd
Copy link

emcd commented Oct 31, 2023

Last week, I made one that does work. The value handling is admittedly non-intuitive and I do think that param synchronization from the HTML+JS side to the Python side is broken, because I am running into similar issues with a custom TextArea that I'm implementing. But, here's the working custom Select for reference:

import param
from panel.reactive import ReactiveHTML

class CompactSelector( ReactiveHTML ):

    options = param.Dict( )
    value = param.String( )
    _style_css__ = param.String( )

    _style_default__ = {
        'appearance': 'none',
        '-moz-appearance': 'none', '-webkit-appearance': 'none',
        'border-radius': '10%',
        # https://stackoverflow.com/a/60236111/14833542
        'text-align': 'center', 'text-align-last': 'center',
        '-moz-text-align-last': 'center',
    }

    _template = '''
        <div class="bk-input-group">
        <select id="CompactSelector"
            class="bk-input"
            onchange="${_select_change}"
            style="${_style_css__}; height: ${model.height}px; width: ${model.width}px;",
            value="${value}"
        >
            {% for option_name, option_value in options.items( ) %}
            <option value="{{option_name}}">{{option_value}}</option>
            {% endfor %}
        </select>
        </div>'''

    def __init__( self, **params ):
        super( ).__init__( **params )
        style = self._style_default__.copy( )
        style.update( params.get( 'style', { } ) )
        self._style_css__ = '; '.join( map(
            lambda pair: ': '.join( pair ), style.items( ) ) )

    def _select_change( self, event ):
        self.value = event.data[ 'target' ][ 'value' ]

Here's an example of it working next to the partially working custom TextArea.
Transition from default value ("freeform prompt") to "canned prompt" value:

image

Transition back from "canned prompt" to "freeform prompt":
image

Additional context...
Data declaration for the widget:

    'selector_user_prompt_class': dict(
        component_class = CompactSelector,
        component_arguments = dict(
            options = {
                'freeform': '\N{Lower Left Ballpoint Pen}\uFE0F',
                'canned': '🥫'
            },
            value = 'freeform',
            align = 'center',
            height = sizes.icon_button_height,
            width = sizes.icon_button_width,
            height_policy = 'fixed', width_policy = 'fixed',
        ),
        event_functions = dict( value = 'on_select_user_prompt_class' ),
    ),

Event handler:

def on_select_user_prompt_class( gui, event ):
    from .updaters import (
        update_and_save_conversation,
        update_chat_button,
        update_summarization_toggle,
    )
    freeform = 'freeform' == gui.selector_user_prompt_class.value
    gui.column_canned_prompt.visible = False
    gui.column_freeform_prompt.visible = False
    gui.column_canned_prompt.visible = not freeform
    gui.column_freeform_prompt.visible = freeform
    update_chat_button( gui )
    update_summarization_toggle( gui )
    update_and_save_conversation( gui )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Something isn't correct or isn't working
Projects
None yet
Development

No branches or pull requests

2 participants