Cannot put the template in the desired outlet

I’m trying to put a template in a specific plugin outlet in my javascripts/discourse/initializers/persistent-banner.gjs.
Code:

import Component from "@glimmer/component";
import { apiInitializer } from "discourse/lib/api";

banner_plugin_outlet = settings.banner_position

export default apiInitializer("1.14.0", (api) => {
  try {
    banner_plugin_outlet = settings.banner_position
    api.renderInOutlet(
      banner_plugin_outlet,
      class persistentbanner extends Component {
        get bannerIsFilled() {
          if (settings.banner_text_content == "") {
            return false;
          } else if (settings.banner_visible == "hide") {
            return false;
          } else {
            return true;
          }
        }
        <template>
          {{#if this.bannerIsFilled}}
            <div class='persistent-banner'>
              <p>
                {{html_safe (theme-setting 'banner_text_content')}}
              </p>
            </div>
          {{/if}}
        </template>
      } 
    );
  } catch (e) {
    console.log(e);
  }
}

But the HTML in the <template> tag won’t display at the outlet location. In fact, it won’t display at all. What am I doing wrong?
Repo link: GitHub - NateDhaliwal/discourse-persistent-banner: A theme component for Discourse that cannot be closed by the user.

1 Like

Don’t use an initialiser for this? Use the connectors folder. There are loads of examples.

2 Likes

The reason is that there are different outlets that can be selected.
I adapted this code from Notification Banner’s repo.

2 Likes

Ah got it. Yes that makes sense. Sorry wasn’t sure if your functional intention. I should have read the code in more detail.

1 Like

A few things to get you going again:

  • this file has an missing closing round bracket at the end of your
    apiInitializer call - that will just not work.

On fixing that issue I see more errors.

  • banner_plugin_outlet is not declared - you need a const here.

    you assign it twice? you don’t need it twice I suspect :slight_smile:

    banner_plugin_outlet = settings.banner_position
    
    export default apiInitializer("1.14.0", (api) => {
      try {
        banner_plugin_outlet = settings.banner_position
    
  • You are missing imports:

    import { htmlSafe } from "@ember/template";
    import themeSetting from "discourse/helpers/theme-setting";
    
  • … but I couldn’t get themeSetting to work as a helper here. No error, just blank, so try this code instead:

            get bannerTextContent() {
              return settings.banner_text_content;
            }
            <template>
              {{#if this.bannerIsFilled}}
                <div class='persistent-banner'>
                  <p>
                    {{htmlSafe this.bannerTextContent}}
    
  • Always check the console for errors.

6 Likes

I imported htmlSafe and this worked like a charm!
Thanks so much!

2 Likes

Yeah, the helper doesn’t work (and isn’t needed) in gjs. Defining a getter is fine. But if you want to avoid that, you can reference the settings “global” directly from the template:

<template>
  {{htmlSafe settings.banner_text_content}}
</template>
4 Likes

Thanks. That didn’t seem very transparent! :sweat_smile:

3 Likes

Yeah that’s fair. Let’s improve the error messages:


5 Likes

Thank you. This really helps with the developer experience.

Which as we know has improved dramatically with.gjs over widgets.

however

There are lots of very odd errors you can get when using gjs components that do not make finding the issues very easy.

For example, lets mess up the helper name:
{{html_safe this.bannerTextContent}}

Leads to the classic:

program.js:100 Uncaught (in promise) TypeError: Invalid value used as weak map key at WeakMap.set (<anonymous>)

(this also happens here with a valid name if you forget the import)

Say what?! :sweat_smile: There are lots of these examples.

I guess this is a downside of using a framework?

3 Likes

Ouch, that’s a bad one!

When I try locally, I see:

Where did you see the WeakMap error? On a production site? If so… perhaps this is one of the checks which ember optimizes out of production builds to improve performance.

If you can, I’d always recommend developing themes/plugins against a proper development environment - there are lots of cases like this where the experience will be better.

4 Likes

Yes, Production site using the Theme CLI ( which I guess is one of its downsides, despite its otherwise it’s a great workflow?)

That makes total sense.

Yes, with plugins it’s my goto but with TCs there’s a good temptation to dev against a Production site because of the immediacy of feedback (if not always very helpful!)

But I’ve just realised, you can enter localhost with the CLI and it works.

So duh!

image

I will use that going forward! :rocket:

I have no idea why I thought that wouldn’t be possible :blush: :sweat_smile:

As usual, thanks for your help that’s saved me a lot of time (in the future :slight_smile: )

2 Likes

Yup! Localhost with a theme-cli is how I try to work, and what I recommend to other people. We can definitely do better at documenting these recommended workflows :eyes:

The other tip is that discourse.theme-creator.io runs with development-mode Ember assets. So that should have the nicer error messages as well.

4 Likes