Observable Framework: include 3rd-party input

First off, thanks for the awesome Observable Framework!

So far, I was unable to make a 3rd party input reactive (the range slider from jquery-ui). I ressorted to jquery-ui as I need a slider to limit a range from both sides in one widget.

I’ve tried

  • hooking the element (as returned by jquery’s $("selector")) to Generators.observe, which failed to attachEventListener though
  • using the slider’s own event handler, which handles doc nodes OK (e. g. changing an <input />'s value) but fails to change a reactive value declared outside the handler

Any hints greatly appreciated!

I haven’t played much with jQuery UI, but I was able to get things working like so.

First, here’s how I installed jQuery UI from npm. (They recommend manually configuring and downloading a build, but I prefer to just import the default configuration from npm if possible so that it’s easier to keep up-to-date.)

<link rel="stylesheet" href="npm:jquery-ui/dist/themes/base/jquery-ui.css">

```js
const $ = self.jQuery = (await import("npm:jquery/dist/jquery.js/+esm")).default;
await import("npm:jquery-ui/dist/jquery-ui.js/+esm");
```

The tricky part is that jquery and jquery-ui aren’t packaged as modern ES modules, so jquery-ui assumes that there’s a jQuery global. This means you have to use a dynamic import and manually assign self.jQuery before importing jquery-ui. It’d be nice if jQuery adopted modern standards. (The /+esm won’t be necessary once #1174 lands.)

Now, to declare the slider:

<p>
  <label for="amount">Price range:</label>
  <input type="text" id="amount" readonly="" style="border:0; color:#f6931f; font-weight:bold;">
</p>

<div style="max-width: 320px;" id="slider"></div>

And the associated JavaScript to initialize it and expose the slider’s value as a reactive variable via Generators.observe:

const value = Generators.observe((notify) => {
  const slider = $("#slider");
  slider.slider({
    range: true,
    min: 0,
    max: 500,
    values: [25, 300],
    slide: (event, ui) => notify(ui.values) // report changed value
  });
  notify(slider.slider("values")); // report initial value
});

Note that there are two calls to notify here: one happens immediately after the slider is initialized to report the initial value; the other happens on each slide event to report the new value after the user moves the slider.

1 Like

Wow - I’d never have expected a fully fledged walkthrough example. Thank you so much! (And for the awesome D3-iverse at that.)

1 Like