Create a Form in a Jupyter Notebook that sets Python Names

Jupyter Notebook: Javascript/Python Bi-directional Communication

Interact with this notebook on Binder here.

In [6]:
# define a Python variable

foo = None
print(foo)
None

Execute JavaScript in the cell by using %%javascript magic.

In [7]:
%%javascript

const kernel = IPython.notebook.kernel;
//The string passed to the execute function has to be valid Python.
kernel.execute('foo = "Hello, from the browser\'s JavaScript world."');

NOTE: If you run all the cells at once, the variable is not set.

This is likely due to the async nature of the JS runtime environment in the browser.

This demo works best by running one cell at a time.

In [8]:
# The Javascript above runs async. Wait for it to finish.
print(foo)
Hello, from the browser's JavaScript world.

The Python variable foo was set to "Hello, from the browser's JavaScript world." by the JavaScript environment.

Display a button by using %%html magic.

Note: After this notebook is parsed into a Nikola blog post, the button does not function.

Try out the executable version of this notebook here.

In [9]:
%%html
<script>
//Using let and const becomes problematic. Have to reload after changes.
var   kernel = IPython.notebook.kernel,
      //Convenient function to add listeners to elements
      on = (el, evt, fn, opts = {}) => {
        const delegatorFn = e => e.target.matches(opts.target) && fn.call(e.target, e);
        el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false);
        if (opts.target) return delegatorFn;
      },
      prefix = 'button click count: ',
      countElement = document.getElementById('count'),
      count = parseInt(countElement.textContent, 10) || 0,
      increment = () => {
          count += 1;
          countElement.textContent = count;
          //The string passed to execute must be valid Python
          kernel.execute(`foo = ${count}`);
          setContent();
      },
      inputElement = document.getElementById('message-input'),
      setMessage = () => {
          //Define a Python variable called "message".
          kernel.execute(`message = "${inputElement.value}"`);
      }
      setContent = () => countElement.textContent = `${prefix}${count}`;
on(document.getElementById('increment'), 'click', increment);
on(inputElement, 'blur', setMessage);
setContent()
</script>
<div class="input-group input-group-sm mb-3">
  <div class="input-group-prepend">
    <span class="input-group-text" id="inputGroup-sizing-sm">Short Message</span>
  </div>
  <input id="message-input" type="text" class="form-control" aria-label="Small" aria-describedby="inputGroup-sizing-sm">
</div>
<p id="count"></p>
<button id='increment' type="submit" class="btn btn-primary">
    Submit
</button>
Short Message

Observe that the Python variable was set inside of the browser's environment.

In [10]:
print(f"The button was clicked {foo} times.\n{message}")
The button was clicked 10 times.
Jupyter notebooks are useful.