0

I have written a simple widget in Jupyter Notebook which is a checkbox table. Now, I am trying to migrate this widget to Jupyter Lab. However, I am unable to find a way to insert JavaScript in a running notebook to build my widget.

I have read the new ipywidget8 tutorial, but I think creating a code package is too heavy for this small feature. I hope to achieve this functionality without building a package, like the ipywidget7 style.

ipywidget8: https://ipywidgets.readthedocs.io/en/8.0.5/examples/Widget%20Custom.html#front-end-typescript

ipywidget7: https://ipywidgets.readthedocs.io/en/7.x/examples/Widget%20Custom.html#Front-end-(JavaScript)

Here is my front-end code:

require.undef("my_widgets");
define("my_widgets", ["@jupyter-widgets/base"], function(widgets) {

  var TableView = widgets.DOMWidgetView.extend({
    // Render the view.
    render: function() {
      this.table_changed();

      // Python -> JavaScript update
      this.model.on("change:table", this.table_changed, this);

      // JavaScript -> Python update
      this.el.onchange = this.input_changed.bind(this);

      // Script
      $(this.el).on("click", ".my-table tbody tr", function (event) {
        if (event.target.type != 'checkbox'){
          $(this).find(".my-chk")[0].click()
        }
      });
    },

    table_changed: function() {
      this.el.innerHTML = this.model.get("table");
    },

    input_changed: function() {
      let value = [];
      let jcheck = $(this.el).find(".my-chk");
      for (let i=0;i<jcheck.length;i++) {
        if (jcheck[i].checked) {
          value.push(i)
        }
      };
      $(this.el).find(".my-table")[0].setAttribute("date-value", value.join());
      this.model.set('value', value);
      this.model.save_changes();
    },
  });
 
  return {
    TableView: TableView,
  };
});

Here is my back-end code:

import traitlets
from jinja2 import Template
from ipywidgets import Layout, DOMWidget, register

@register
class TaskTable(DOMWidget):
    _view_name = traitlets.Unicode('TableView').tag(sync=True)
    _view_module = traitlets.Unicode('my_widgets').tag(sync=True)

    value = traitlets.List([], help="selected").tag(sync=True)
    table = traitlets.Unicode('', help="rendered HTML table").tag(sync=True)

    @traitlets.validate('value')
    def _valid_value(self, proposal):
        proposal['value'] = [int(x) for x in proposal['value']]
        return proposal['value']

    def render(self, head, body):
        thead = ['#'] + head
        tbody = body
        self.table = template.render(head=thead, body=tbody)
        
template = Template(STATICS_TaskTable)

STATICS_TaskTable = """
<table class="my-table">
<thead>
<tr>
  {%- for th in head -%}
  <th>{{ th }}</th>
  {%- endfor %}
</tr>
</thead>
<tbody>
  {%- for row in body -%}
  <tr>
    {%- for cell in row -%}
      {%- if loop.first -%}
        <th><input class="my-chk" type="checkbox"> {{ cell }}</th>
      {%- else -%}
        <td>{{ cell }}</td>
      {%- endif -%}
    {%- endfor -%}
  </tr>
  {%- endfor -%}
</tbody>
</table>
"""

w = TaskTable()
w.render(['foo', 'bar'], [[1, 'A', 'S'], [2, 'D', 'F']])
w

I tried to add jQuery and RequireJS to the page, but only got an error message Error displaying widget: model not found

I could not found a page like "front-end-javascript" in the ipywidget8 tutorial.

0 Answers0