Ein Widget neu laden/aktualisieren, wenn ein anderes Widget aktualisiert wird

Hallo zusammen,

wir haben ein Widget namens „topic-timeline-bookmark" erstellt, das den Lesezeichen-Button auf Themen-Ebene nach dem Widget „topic-timeline" anzeigt.

Wenn wir nun auf den Lesezeichen-Button von topic-timeline klicken, wird das Modal-Fenster zum Festlegen des Lesezeichens angezeigt. Beim Speichern des Lesezeichens werden die Lesezeichen-Buttons unter den first-post-menu-Buttons und den topic-footer-button aktualisiert, aber der Button von topic-timeline selbst wird nicht aktualisiert, bis das Widget topic-timeline neu geladen wird (d. h. bis wir scrollen), und umgekehrt.

first-post-menu

image


topic-footer-button

image

Ich habe festgestellt, dass das Widget post-stream immer dann neu geladen wird, wenn ein Lesezeichen gesetzt oder entfernt wird. Daher funktionieren die Lesezeichen-Buttons im Post-Menü und im topic-footer-button synchron.

Wie kann ich nun mein Widget „topic-timeline-bookmark" immer dann neu laden, wenn ein Lesezeichen gesetzt oder entfernt wird oder wenn das Widget post-stream neu geladen wird? Hier ist mein Code:

<script type="text/discourse-plugin" version="0.8">
  const { h } = require('virtual-dom');
  const { getOwner } = require("discourse-common/lib/get-owner");
  const topicController = getOwner(this).lookup("controller:topic");

  api.createWidget("topic-timeline-bookmark", {  
      tagName: 'div.discourse-bookmark-button-wrapper',
      buildKey: () => `topic-timeline-bookmark`,
      toggleBookmark() {
        topicController.send('toggleBookmark');
      },
      html(attrs, state) { 
        let contents = [];
        const user = api.getCurrentUser();
        if (user) {
            let tooltip = 'bookmarked.help.bookmark';
            let label = 'bookmarked.title';
            let buttonClass = 'btn btn-default bookmark';
            let icon = "bookmark";  
            let bookmarkedPosts = topicController.model.bookmarked_posts;
            let bookmarkCount = 0;

            if(bookmarkedPosts && bookmarkedPosts.length > 0){
              bookmarkCount =  bookmarkedPosts.length;
              
              //Icon
              if (bookmarkedPosts.some((bookmark) => bookmark.reminder_at))
                icon = "discourse-bookmark-clock";
              else
                icon = "bookmark";

              //Label
              if (bookmarkCount === 0)               
                  label = "bookmarked.title";          
              else if (bookmarkCount === 1)
                  label = "bookmarked.edit_bookmark"; 
              else 
                  label = "bookmarked.clear_bookmarks";

              //Tooltip
              if (bookmarkedPosts.length === 1)
                  tooltip = 'bookmarked.help.edit_bookmark';
              else if (bookmarkedPosts.find((x) => x.reminder_at))
                  tooltip = 'bookmarked.help.unbookmark_with_reminder';
              
              //Append CSS class if bookmark is set
              if (bookmarkCount > 0) { buttonClass += ' bookmarked' }
            }
    
            contents.push(
            this.attach('button', {
              action: 'toggleBookmark',
              title: tooltip,
              label: label,
              icon: icon,
              className: buttonClass
            })
          );
        }
        return contents;
      }, 
    });
 
  api.decorateWidget('topic-timeline:after', function(helper) {
    return helper.attach('topic-timeline-bookmark');
  });
</script>
2 „Gefällt mir“

Vielen Dank, dass Sie sich gemeldet haben. Einer unserer Entwickler wird sich dies ansehen und mit hilfreichen Informationen zurückmelden.

3 „Gefällt mir“

Hallo,

ich habe es lokal noch nicht ausprobiert, aber folgender Ansatz könnte funktionieren:

Füge in deinem Hauptskript diesen API-Aufruf hinzu:

api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');

In deinem Widget-Code deklariere diese Funktion:

api.createWidget("topic-timeline-bookmark", {  
  // Code weggelassen

  // Möglicherweise könnte man es direkt im API-Aufruf statt 'force-refresh'
  // 'schedule-rerender' nennen und diese Funktion somit vermeiden
  forceRefresh() {
    this.scheduleRerender();
  }
});

Ich denke, das sollte funktionieren. Falls nicht, lass es mich bitte wissen, dann versuche ich, lokal ein funktionierendes Beispiel zu erstellen.

3 „Gefällt mir“

Vielen Dank für deine Antwort, @joffreyjaffeux.

Wir haben den von dir vorgeschlagenen Code ausprobiert, aber er funktioniert nicht.

  1. Wir haben den folgenden API-Aufruf hinzugefügt:
    api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');
    Und danach die Methode forceRefresh() im Widget „topic-timeline-bookmark" hinzugefügt.
    Das funktioniert jedoch nicht.

  2. Ich habe auch versucht, den zweiten Parameter der dispatchWidgetAppEvent-Methode in „schedule-rerender" umzubenennen und die forceRefresh-Funktion aus dem Widget zu entfernen. Auch das funktioniert nicht.

Ich habe mir die Implementierung der api.dispatchWidgetAppEvent-Methode angesehen. Sie nimmt drei Argumente entgegen, wobei das zweite der widgetKey ist. Ich denke, dies sollte der Wert sein, der von der buildKey()-Funktion des Widgets zurückgegeben wird.
Das dritte Argument ist das appEvent, das in camelCase umgewandelt und als Methodenname für uns verwendet wird.

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L1448

Übersehen wir etwas?

Ich werde es lokal versuchen, ich habe wahrscheinlich einen Fehler gemacht.

1 „Gefällt mir“

@saurabhmasc Ich habe es lokal zum Laufen gebracht, musste jedoch einen Fehler im Core beheben und eine neue Funktion im Core hinzufügen. Ich werde das Thema aktualisieren, sobald alles zusammengeführt ist.

3 „Gefällt mir“

Danke, @j.jaffeux.

Hallo @j.jaffeux,

Hast du eine Ahnung, wann diese Änderungen zusammengeführt werden?

1 „Gefällt mir“

Hallo, ja, ich habe es gerade zusammengeführt (du musst es also zuerst bereitstellen): DEV: adds a topic level bookmark toggle (#14471) · discourse/discourse@20e70d0 · GitHub

Außerdem ist dies eine Beispielkomponente, die ich dafür erstellt habe:

Lass mich wissen, falls du Fragen hast.

3 „Gefällt mir“

Hallo @j.jaffeux,

  1. Wir haben festgestellt, dass früher, wenn wir über die Topic-Footer-Buttons ein Lesezeichen gesetzt haben, auch der erste Beitrag als gelistet markiert wurde. Jetzt wird der erste Beitrag jedoch nicht mehr gelistet. Ist das jetzt korrekt?

  2. Wir haben Ihre Komponente in allen Fällen getestet und sie funktioniert einwandfrei. Lediglich die Funktion „Lesezeichen löschen“ arbeitet nicht synchron.
    Um dies zu beheben, haben wir folgende Codezeilen hinzugefügt, und jetzt funktioniert die Funktion „Lesezeichen löschen“ ebenfalls einwandfrei:

  api.dispatchWidgetAppEvent(
    "topic-timeline",
    "topic-timeline-bookmark",
    "post-stream:refresh"
  );

Vielen Dank.

1 „Gefällt mir“

Ich werde den ersten Punkt prüfen. Was den zweiten betrifft: Ja, es ist möglich, dass ich einen Fall übersehen habe. Der Hauptautor der Lesezeichen ist derzeit abwesend, und ich möchte ein paar Dinge ändern, aber dafür muss er zurück sein. Deine Korrektur sollte in Ordnung sein.

3 „Gefällt mir“

Nach verschiedenen Tests denke ich, dass dies das erwartete Verhalten ist (und nicht mit der Komponente zusammenhängt).

1 „Gefällt mir“

Danke für dein Feedback, @j.jaffeux.

Wir werden ein neues Ticket erstellen und bitten, diese Kernänderungen in unsere Staging- und Produktionsumgebungen zu übernehmen, damit wir sie in Staging testen können.

2 „Gefällt mir“