holoviz / panel

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

JSComponent should document `_rename` #7442

Open ahuang11 opened 1 month ago

ahuang11 commented 1 month ago

Without the following, bokeh raises a serialization error bokeh.core.serialization.SerializationError: can't serialize <class 'function'>, but https://panel.holoviz.org/reference/custom_components/JSComponent.html doesn't mention anything about it.

    _rename = {"event_drop_callback": None}
import panel as pn
import param
from panel.custom import JSComponent

pn.extension()

class SimpleFullCalendar(JSComponent):

    event_drop_callback = param.Callable(
        doc="""
    A callback that will be called when an event is dropped on the calendar.
    """
    )

    _esm = """
     import { Calendar } from '@fullcalendar/core';
    import dayGridPlugin from '@fullcalendar/daygrid';
    import interactionPlugin from '@fullcalendar/interaction';

    export function render({ model, el }) {

      let calendar = new Calendar(el, {
        plugins: [ dayGridPlugin, interactionPlugin ],
        editable: true,
        eventDrop(info) {
          model.send_msg({event_drop: JSON.stringify(info)})
        },
        events: [
          { title: 'event 1', date: '2024-10-01' },
          { title: 'event 2', date: '2024-10-02' }
        ]
      });

      calendar.render()
    }
    """

    _importmap = {
        "imports": {
            "@fullcalendar/core": "https://cdn.skypack.dev/@fullcalendar/core@6.1.15",
            "@fullcalendar/daygrid": "https://cdn.skypack.dev/@fullcalendar/daygrid@6.1.15",
            "@fullcalendar/interaction": "https://cdn.skypack.dev/@fullcalendar/interaction@6.1.15",
        }
    }

    _rename = {"event_drop_callback": None}

    def _handle_msg(self, msg):
        import json
        if "event_drop" in msg:
            if self.event_drop_callback:
                self.event_drop_callback(json.loads(msg["event_drop"]))

calendar = SimpleFullCalendar(event_drop_callback=lambda event: print(event))
calendar.show()
MarcSkovMadsen commented 3 weeks ago

I had the same issue here

Image

So far I've been using precedence=-1 which I felt was a hack. This is a much better solution. Should be documented.

I think I've reported it elsewhere as a request for a sync=False attribute on a parameter similar to what Ipywidgets supports. I could not find that request though. And _rename solution is a great solution.