Live updates of components

I have a component that looks like this:

<td class="topic-rating">
  <span class="rating-title">{{ratingName}}</span> 
     <form>
        <input type="hidden" name="topic_id" value="{{topic.id}}">
        {{#unless useNames}}{{ratingLow}}{{/unless}}
        {{#each this.ratingOptions as |option|}}
            <RadioButton
              @name={{option.name}}
              @value={{option.value}}
              @selection={{this.myRating}}
              @onChange={{this.submitRating}}
            />
            {{#if useNames}} <span class="rotated-label">{{option.label}}</span>{{/if}}
        {{/each}}
        {{#unless useNames}}{{ratingHigh}}{{/unless}}
    </form>
</td>

The ratings are an array added to the topic_view serializer and have topic_id and rating_id in each array item.

And I have this supporting js:

...
export default class TopicRatingComponent extends Component {
  get myRating() { 
    const ratingId = this.args.id;
    const rating = this.args.topic.user_ratings.find((rating) => Number(rating.rating_id) === Number(ratingId));
    return rating?.rating_value;
  }
...

It works as expected. And when I click on of the RadioButtons it calls a function that does a POST and updates a custom model that’s added to the topic serializer. If I reload the page, everything is expected, but I want those radio buttons to update live (right now, multiple radio buttons remain lit if you change it multiple times).

My controller does this:

      MessageBus.publish("/topic/#{params[:topic_id]}", reload_topic: true)

So I think the stuff should be getting updated in the topics displayed in the topic list.

I think the issue is that I need to be using @discourseComputed instead of get, but when I do, I get an error. Maybe I can’t use @discourseComputed in a component? Maybe I need to do some kind of . . . something else?

EDIT: I asked chatGPT and it says that I need do so something with
import { tracked } from '@glimmer/tracking';, so I’m trying that now. . .

1 Like

So I did it. I think that these bits might be helpful for someone else, so here’s what I was missing in the component:

This is far from generally useful documentation, but maybe it will help someone if they need it (or maybe I’ll find it next time I need it!).

import { tracked } from '@glimmer/tracking';
...
  @tracked myRating

 constructor() {
    super(...arguments);
    this.userRatings = this.args.topic.user_ratings;  // Initialize tracked property
    if (!this.args.topic.user_ratings) {
      return [];
    }
    const ratingId = this.args.id;
    const rating = this.args.topic.user_ratings.find((rating) => Number(rating.rating_id) === Number(ratingId));
    this.myRating = rating?.rating_value;
    }

....
 // and then in the action that changes the value:
        this.myRating = Number(newStatus);
2 Likes