A question about developing widgets... Did I misunderstand something?

If I don’t call this.execute() in render() but call this.execute() in initialise and refresh, then the class properties set in execute won’t work.

For example, the following code (written in TypeScript, but does not affect reading):

But I printed some logs and found that execute and initialise in update do get called, and before render; also, if I print this and this.value1 in update, I find that value1 in this does change, but this.value1 does not.

import { TWElement, IParseTreeNode, IWidgetInitialiseOptions } from 'tw5-typed';
import { widget as Widget } from '$:/core/modules/widgets/widget.js';

class TestWidget extends Widget {
  value1: string = '1';
  value2: string = '3';

  execute() {
    this.value1 = '2';
  }

  initialise(parseTreeNode: IParseTreeNode, options: IWidgetInitialiseOptions) {
    super.initialise(parseTreeNode, options);
    this.computeAttributes();
    this.execute();
  }

  update() {
    this.computeAttributes();
    this.execute();
  }

  render(parent: TWElement, nextSibling: TWElement) {
    this.value2 = '4';
    this.domNodes.push(
      parent.insertBefore(
        $tw.utils.domMaker('div', { text: `value1:${this.value1}, value2:${this.value2}` }),
        nextSibling,
      ),
    );
  }
}

exports['test-widget'] = TestWidget;

and Use it(<$test-widget>), with the content of value1:1, value2:4.


Hi @Sttot I am not familiar with TypeScript. I assume TestWidget inherits the constructor from the Widget class? What is the update() method for? It doesn’t appear to be called.

I note that the render() method is not calling this.computeAttributes() as I would have expected.

I will admit that writing a widget does get quite confusing to me. A part of the problem is that instead of using hooks which can rely on super it all funnels through render() which has a bunch of requirements to call methods on itself. The docs do not offer much in the way of “do this”, “do that” to make it work. As a developer I don’t know which methods I must call, when to call them, or if a method is optional.

It would be really nice is a different widget interface was available that would take care of the boilerplate for you calling the underlying methods as expected/needed while leaving the business logic front and center in the child inheriting class/widget.

Eventually I will get motivated enough to deep dive and write a cheat sheet for them.

2 Likes