Search code examples
pythoninputbokeh

Adding a custom datepicker to bokeh standard text input


I'm trying to add a standard datepicker (like air datepicker) to a standard bokeh text input.

I added the JS references and I'm linking a class in the text input field like:

event = TextInput(title=u"Event Date", value=' ', css_classes=['datepicker-here'])

In theory, that should work, yet, it is not... I also tried with other standard datepicker, to no success.

Here is another case: flatpicker. A simple datepicker which works perfectly with this setup:

Create a simple text input:

event = TextInput(title=u"event", css_classes=['flatpkr'])

and put the required js code in the template.

flatpicker examples here (how it should work):

$("input[type='text']").flatpickr({
    enableTime: true,
    dateFormat: "F, d Y H:i"
});
<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/flatpickr.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/themes/dark.css">
</head>
<body>
  <div>
    <input type="text" placeholder="Please select Date Time">
  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/flatpickr.js"></script>
</body>

If this is set in a plain webpage, everything is working properly. In Bokeh it does not, although I set exactly the same code in the template

{% extends base %}

{% block postamble %}
  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/flatpickr.css">
{% endblock %}

{% block contents %}
    {{ super() }}
    <!-- JS Scripts -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

    <!-- Flatpicker -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/flatpickr.js"></script>
    <script type="text/javascript">
        flatpickr("input[type='text']", {
            "minDate": new Date().fp_incr(1)
        });
    </script>
{% endblock %}

Solution

  • The extra information confirms what I thought you intended, but is not actually enough to run and investigate. That said, contrary to your supposition "In theory, that should work", I would actually never expect this to work. And the reason is that declaring a Bokeh TextInput does mean "just dump a bare <input> in the DOM". Rather, there is an entire JS implementation and CSS that Bokeh provides to support its version of a text input widget. In general, I have zero confidence that it would ever "just work" to have two different JS libraries fighting to control the same DOM element in their own separate ways.

    If you want to do this sort of thing (i.e. integrate outside widgets seamlessly with Bokeh), it's possible, but the usual mechanism is by Extending Bokeh. In particular see the example Adding a Custom Widget. A custom extension will have a Python object that represents it and that is automatically synchronized the same as any other Bokeh object.

    Another (simpler) possibility: You could put HTML (including your plain <input>) in a Bokeh Div. Bokeh won't try to style or control any DOM elements added inside a Div. That might reasonably be expected to work (though I have not tried). A widget added this way will not have a Python counterpart that it is automatically synced with, but its not clear what your actual requirements are, so that might be fine.