Reload/Refresh a widget on refresh of another widget

Hi All,

We have created a widget “topic-timeline-bookmark” that displays the topic-level Bookmark button after the topic-timeline widget.

Now, whenever we click on the topic-timeline bookmark button it displays the modal box to set the bookmark and when we save the bookmark it updates the Bookmark buttons under the first-post-menu buttons and topic-footer-button but does not update itself until the topic-timeline widget is not refreshed (i.e. until we scrolling) and vice versa.





I found that whenever Bookmark is set/unset post-stream widget is refreshed so the post-menu and topic-footer-button Bookmark buttons work in sync.

So now how can I refreshed my “topic-timeline-bookmark” widget whenever Bookmark is set/unset or whenever post-stream widget is refreshed? below is my 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() {
      html(attrs, state) { 
        let contents = [];
        const user = api.getCurrentUser();
        if (user) {
            let tooltip = '';
            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;
              if (bookmarkedPosts.some((bookmark) => bookmark.reminder_at))
                icon = "discourse-bookmark-clock";
                icon = "bookmark";

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

              if (bookmarkedPosts.length === 1)
                  tooltip = '';
              else if (bookmarkedPosts.find((x) => x.reminder_at))
                  tooltip = '';
              //Append CSS class if bookmark is set
              if (bookmarkCount > 0) { buttonClass += ' bookmarked' }
            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');

Thank you for reaching out, one of our developers are going to look into this and report back with some helpful information.



I haven’t tried it locally but something that might work:

In your main script add this api call:

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

In your widget code, declare this function:

api.createWidget("topic-timeline-bookmark", {  
  // code omitted

  // might be able to name it schedule-rerender 
  // directly in the api call instead of force-refresh
  // and avoid having this function
  forceRefresh() {

I think this should work, if it doesn’t let me know, I will try to build a working example locally.


Thanks, @joffreyjaffeux for the reply.

We have tried the code suggested by you, but it’s not working.

  1. Added the below api call
    api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');
    And then add the forceRefresh() method in “topic-timeline-bookmark” widget.
    But it is not working.

  2. I also try to rename the second parament of the dispatchWidgetAppEvent method to “schedule-rerender” and removed the forceRefresh function from the widget. This also not works.

I look for the implementation of the api.dispatchWidgetAppEvent method it takes 3 arguments where the second is widgetKey, I think it should be the value returned by the buildKey() function of the widget.
And the third argument is the appEvent which is converted to camelCase and used as the method name for us

Are we missing something?

I will try locally, I probably have made a mistake.

1 Like

@saurabhmasc I made it work locally, however I had to fix a bug in core and also add a new feature in core. I will update the topic when this is all merged.


Thanks, @joffreyjaffeux.

Hi @joffreyjaffeux,

Any idea when these changes will be merged.

1 Like

Hi, yes I just merged it (so you will ned to have it deployed first): DEV: adds a topic level bookmark toggle (#14471) · discourse/discourse@20e70d0 · GitHub

Also this is an example component I made for this:

Let me know if you have any question.


Hi @joffreyjaffeux ,

  1. Now we observed that before when we bookmark from the topic-footer-buttons then the first post was also marked as booked, but now the first post is not getting booked, is it correct now?

  2. We have tested your component all the cases working fine, only Clear bookmark functionality is not working in sync.
    To make it work, we have added the below lines of code, and now Clear bookmark functionality also works fine.



1 Like

Will look at the first point. Concerning the second yes it’s possible I forgot a case, the main author of bookmarks is away atm and I would like to change few things but I need him to be back, your fix should be ok.


After various tests I think this is expected (and not related to the component).

1 Like

Thanks, @joffreyjaffeux for your feedback.

We will create a new ticket, requesting for having these core changes to our Staging and Production environments. So we can test it on Staging.