Vanilla JavaScript with Preact signals example

A View is constructed with a host element: a DOM element in which child elements/views will be created:

class TextField extends View {
  constructor(hostElem, nameSignal) {
    super(hostElem);

    this.nameSignal = nameSignal;
  }

Above, the nameSignal is a Preact signal.

In setup(), construct the elements and sub-views:

  setup() {
    this.inputElem = document.createElement("input");
    this.inputElem.setAttribute("type", "text");
    this.inputElem.value = this.nameSignal.value;
    this.inputElem.oninput = ((e) => {
      let value = e.target.value;
      this.nameSignal.value = value;
    })
    this.hostElem.appendChild(this.inputElem);
  }

In update(), update the existing elements:

  update() {
    this.inputElem.value = this.nameSignal.value;
  }
}

The main/root view could be implemented like this, creating the necessary signals and setting up sub-views:

class AppView extends View {
  constructor(hostElem) {
    super(hostElem);

    this.name = signal("Bob");
  }

  setup() {
    this.addSubView(new BtnView(this.hostElem, "me"))

    let b2 = new BtnView(this.hostElem, "us")
    this.addSubView(b2);

    let b3 = new SharedBtnView(this.hostElem, b2.count);
    this.addSubView(b3);

    this.addSubView(new TextField(this.hostElem, this.name));
    this.addSubView(new TextField(this.hostElem, this.name));
  }
}

Putting it all together:

const appElem = document.querySelector("#app");
let view = new AppView(appElem);
view.connect();

The connect() method connects everything up. It is part of the View superclass:

class View {
  constructor(hostElem) {
    this.hostElem = hostElem;
    this.subViews = [];
  }

  connect() {
    this.setup();

    for (let subView of this.subViews) {
      subView.connect()
    }

    effect(() => {
      this.update();
    });
  }

  addSubView(subView) {
    this.subViews.push(subView);
  }

  setup() {}

  update() {}
}
Note last edited December 2024.
Incoming links: You might not need React.