A tour of how the Widget (Virtual DOM) code in Discourse works

Right, after a lot of headaches I’ve got it working - thanks for the help! :tada:

The two other problems I hit which could possibly do with some re-engineering in the widget code:

  • When setting dirtyKeys, it only re-renders the first widget with that buildKey. I’ve got around that by adding the post-id to the post-avatar’s buildKey so that every buildKey is unique
  • Setting the dirtyKey doesn’t work if the widget you want to re-render is inside another widget. In my case the post-avatar is inside a post. I think this is because of the shadowTree stuff.
    It would be really nice if the widget code could work out that the widget is deep in the tree and re-render its parents. I’ve got around this by setting the post widget as dirty as well.

That’s because keys are supposed to be unique! So adding the post id to the avatar is correct in this case. I might want to raise an error in development mode if two elements use the same keys. If you want to commit the post avatar key to master that would be fine.

That’s exactly what it is. By default I think a widget is supposed to re-render its parents, but the shadowTree is a performance optimization that avoids too much re-rendering and requires you to be more explicit.

Just in case anyone is trying to track down how widgets can use handlebars templates, see the commit message here (can’t find it documented anywhere on meta):

https://github.com/discourse/discourse/commit/dffb1fc4ee8a4d58f48145decb1590a304e8cf7d

So erstellen Sie eine Navigationsleiste: Mit einem Widget.

So ähnlich

image

Der folgende Code in der Anleitung funktioniert nicht mehr. Die Darstellung funktioniert, aber der Zähler wird bei Klicks nicht erhöht:

<script type="text/javascript">
        const { createWidget } = require('discourse/widgets/widget');

        createWidget('increment-button', {
            tagName: 'button',

            defaultState() {
                return { clicks: 0 };
            },

            html(attrs, state) {
                return `Click me! ${state.clicks} clicks`;
            },

            click() {
                this.state.clicks++;
            }
        });
</script>


<script type='text/x-handlebars' data-template-name='/connectors/above-footer/increment-button'>
    {{mount-widget widget="increment-button" }}
</script>

Seltsam, bei mir wird diese Komponente gar nicht gerendert, da eine key-Eigenschaft fehlt. Ich habe die obige Dokumentation aktualisiert und eine buildKey-Methode hinzugefügt, und bei mir funktioniert es jetzt. Probier das mal aus.

Danke @eviltrout, das hat funktioniert! Sehr zu schätzen.

Wie kann ich HTML, das aus einem Argument stammt, im Widget rendern? Momentan wird das HTML entgültigt und so ausgegeben, wie es ist.

Auch das folgende Beispiel funktioniert nicht:

Es scheint, als wäre die Variable user null. Muss ich etwas tun, um user in das HBS zu übergeben, von dem aus das Widget gemountet wird?

Die Antwort darauf habe ich gefunden:

Antwort:

import { createWidget } from 'discourse/widgets/widget';
import RawHtml from "discourse/widgets/raw-html";

createWidget('display-name', {
  tagName: 'div.name',

  html() {
    return new RawHtml({ html: `<div>${this.siteSettings.user_rank_alert_message}</div>` });
  }
});

Aber ich weiß immer noch nicht, wie ich Benutzerdaten in einem Connector-HBS bekomme, wenn die Daten nicht vom Outlet übergeben werden.

schau dir die drei geschweiften Klammern an, Bro :smiley:

Nicht so schnell :wink: :warning: :

Anstelle von dreifachen geschweiften Klammern können Sie stattdessen einen Helfer verwenden:

{{html-safe result}}

Hey @eviltrout,

ich habe im OP dieses Threads gesehen, dass du schreibst:

Aber weiter unten im Thread erwähnst du:

Wärst du bereit, den OP zu korrigieren?

Danke, ich habe diese Änderung vorgenommen.

@eviltrout Sollte das nicht action="deleteThing" sein?

Es hängt von Ihrem Widget ab. In @eviltrouts Beispiel erwartet das my-widget, dass ihm eine Aktion namens „deleteThing“ übergeben wird. Verschiedene Widgets verwenden unterschiedliche Namen für ihre Aktionen (und tatsächlich ist es möglich, dass sie ihre Aktion „action“ nennen).