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

Comment créer une barre de navigation ? à l’aide d’un widget.

comme ceci

image

Le code suivant dans l’instruction ne fonctionne plus. Le rendu fonctionne, mais l’état n’incrémente pas lors des clics :

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

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

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

            html(attrs, state) {
                return `Cliquez-moi ! ${state.clicks} clics`;
            },

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


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

Étrange, pour moi, lorsque j’essaie ce composant, il ne se rend pas du tout car il manque une key. J’ai mis à jour la documentation ci-dessus pour ajouter une méthode buildKey et cela fonctionne pour moi. Essayez cela.

Merci @eviltrout, j’ai réussi à faire fonctionner cela ! Beaucoup d’appréciation.

Comment puis-je rendre du HTML provenant d’un argument dans le widget ? Actuellement, le HTML est échappé et affiché tel quel.

De plus, l’exemple suivant ne fonctionne pas :

Il semble que la variable user soit null. Dois-je faire quelque chose pour transmettre user au HBS depuis lequel le widget est monté ?

J’ai trouvé la réponse à cette question :

Réponse :

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>` });
  }
});

Mais je ne sais toujours pas comment obtenir les données de l’utilisateur dans un hbs de connecteur où les données ne sont pas transmises depuis la prise de sortie.

Regarde les triple accolades, mec :smiley:

Pas si vite :wink: :warning: :

Au lieu des accolades triples, vous pouvez utiliser un helper à la place :

{{html-safe result}}

Salut @eviltrout,

J’ai remarqué dans le message d’origine de ce sujet que tu dis :

Mais plus bas dans ce sujet, tu mentionnes :

Serais-tu disposé à corriger le message d’origine ?

Merci, j’ai apporté cette modification.

@eviltrout Ne devrait-ce pas être action="deleteThing" ?

Cela dépend de votre widget. Dans l’exemple de @eviltrout, my-widget s’attend à recevoir une action nommée « deleteThing ». Différents widgets utiliseront des noms différents pour leurs actions (et en fait, il est possible qu’ils nomment leur action « action »).