observablehq / stdlib

The Observable standard library.
https://observablehq.com/@observablehq/standard-library
ISC License
966 stars 83 forks source link

Add View class? #39

Closed mbostock closed 3 years ago

mbostock commented 6 years ago

As shown in https://beta.observablehq.com/@mbostock/views-are-mutable-values

class View {
  constructor(value) {
    this._list = [];
    this._value = value;
  }
  get value() {
    return this._value;
  }
  set value(value) {
    this._value = value;
    this.dispatchEvent({type: "input", value});
  }
  addEventListener(type, listener) {
    if (type != "input" || this._list.includes(listener)) return;
    this._list = [listener].concat(this._list);
  }
  removeEventListener(type, listener) {
    if (type != "input") return;
    this._list = this._list.filter(l => l !== listener);
  }
  dispatchEvent(event) {
    const p = Promise.resolve(event);
    this._list.forEach(l => p.then(l));
  }
}
mbostock commented 4 years ago

Or even simpler:

class View extends EventTarget {
  constructor(value) {
    super();
    Object.defineProperties(this, {
      _value: {value, writable: true}
    });
  }
  get value() {
    return this._value;
  }
  set value(value) {
    this._value = value;
    this.dispatchEvent({type: "input", value});
  }
}

But Safari doesn’t support extending EventTarget yet, boo.

mbostock commented 3 years ago

Fixed in #207.

mootari commented 3 years ago

For reference, #207 adds @observablehq/inputs as a built-in, which in turn provides the inputs widget that matches the interface described above.