Is there a better way to make an ajax request from a theme component?

I’ve built a theme component that renders when you’re viewing a user’s profile. It makes an ajax request to a separate website (which I control) to check whether the discourse user has an account there (sending the discourse user id in the url). If so, it renders a link to their account on that website.

It’s working, but I’m fairly certain it’s awful hackery that would make a discourse developer sick! So I wanted to ask whether there’s a better way to do it? I’m a JavaScript and ruby developer, but I’ve never worked with Ember (I’ve used Vue, Backbone, and React).

<script type="text/discourse-plugin" version="0.8.7">
    const {ajax} = require('discourse/lib/ajax')

    api.registerConnectorClass('user-profile-primary', 'custom-profile-link', {
      setupComponent(args, component) {
        args.model.get('fetchPersonnelMember')
      }
    })
    
    api.modifyClass('model:user', {
      fetchPersonnelMember: function () {
        console.log('running!', ajax)
        const urlTemplate = settings.personnel_lookup_url // e.g. "https://api.29th.org/members?discourse_id=%s"

        const url = urlTemplate.replace(/%s/, this.id)
        return ajax(url).then((result) => {
            if (result.status == true && result.member.id) {
              this.setProperties({personnelMember: result.member})
            }
          })
      }.property('id'),
      
      personnelLinkUrl: function () {
        if (this.personnelMember) {
          const viewUrlTemplate = settings.personnel_view_url // e.g. "https://personnel.29th.org/#members/%s"
          return viewUrlTemplate.replace(/%s/, this.personnelMember.id)
        }
      }.property('personnelMember'),
      
      personnelLinkName: function () {
        return this.personnelMember ? this.personnelMember.short_name : ''
      }.property('personnelMember')
    })
</script>

<script type='text/x-handlebars' data-template-name='/connectors/user-profile-primary/custom-profile-link'>
  {{#if model.personnelLinkUrl}}
    <div class="public-user-fields">
      <div class="public-user-field">
        <span class="user-field-name">
          {{theme-setting 'personnel_label'}}
        </span>
        <span class="user-field-value">
          <a href="{{{model.personnelLinkUrl}}}">{{model.personnelLinkName}}</a>
        </span>
      </div>
    </div>
  {{/if}}
</script>

I derived this mostly from Link custom user field to external website - #24 by LeoMcA. My guess is the main problem is I’m using a computed property to run an async function, which is a no-no. Instead, I should be running that async request in some sort of “on load” hook (but only when I’m on the user profile page).

I also feel like I’m reinventing the wheel a little with the template format of the variables. Ideally, I’d make this a configurable plugin that I’d share, so it would be nice if the settings could look more like a handlebars template, e.g. https://mysite.com/members/{{id}}, but I didn’t see any utilities or helpers for this in the discourse codebase.

I’d welcome your feedback! Thanks for your time.

2 Likes

I hope bumping is okay because I could really use a steer on this one :slight_smile:

1 Like

If you can use a plugin instead, I’d do the request server side (and store the data if it’s stable) and add the link to the serializer.

I think there is a theme component that adds other topic lists the three top of the page like feverbee does. It might have the example you need.