In a Dev category discussion, user Andrew_Rowe sought help rendering the first posts of specific topics above the discovery list in the discovery-list-container-top outlet. Initially struggling with syntax errors when using the static template property in a GJS file within the theme editor, Andrew shared several code attempts.
User NateDhaliwal provided a working solution, suggesting the removal of static template in favor of a direct <template> tag and replacing fetch with Discourse’s ajax helper along with htmlSafe for content rendering. Nate noted that the error likely stemmed from the static template syntax not being compatible with the specific initialization method in the theme editor NateDhaliwal.
User merefield clarified that the choice between let and const was not the issue. They explained that the <template> syntax is likely only fully supported in standalone .gjs files rather than the online theme editor, suggesting that moving the project to GitHub would resolve these limitations merefield.
Andrew confirmed that Nate’s code worked successfully and decided to migrate his theme to GitHub to avoid future constraints. He expressed gratitude for the community’s assistance, particularly noting the value of ask.discourse.org in resolving his technical challenges.
Thank you Nate! I’m trying to figure out what you changed
Your code seems to match my first version
You have replaced let with const in the for loop
is that correct?
ask discourse version throws error
for (let id of topicIds) {
let res = await fetch(`/t/${id}.json`);
let data = await res.json();
if (data.post_stream && data.post_stream.posts.length > 0) {
posts.push(data.post_stream.posts[0]);
}
}
Nate’s version runs
for (let id of topicIds) {
const res = await fetch(`/t/${id}.json`);
const data = await res.json();
if (data.post_stream && data.post_stream.posts.length > 0) {
posts.push(data.post_stream.posts[0]);
}
}
Can anyone explain what is wrong? Why Let wouldn’t work and const does?
I tried let and the result was the same. It’s just that I’d normally use const when using fetch() or ajax().
I believe the error comes from the static template = line. With it, I get:
[THEME 10283 'Pokemon Theme'] Error: connector component has no associated template. Ensure the template is colocated or authored with gjs.
at h (plugin-connectors.js:35:11)
at eY.renderInOutlet (plugin-api.gjs:1116:5)
at todo.gjs:43:7
at eH (plugin-api.gjs:3363:10)
at Object.initialize (api.js:21:14)
at i.initialize (app.js:265:28)
at index.js:379:19
at e.each (index.js:183:7)
at e.walk (index.js:112:10)
at e.each (index.js:59:20)
at e.topsort (index.js:65:10)
at iL._runInitializer (index.js:392:11)
at iL.runInstanceInitializers (index.js:377:10)
at l._bootSync (instance.js:116:22)
at iL.didBecomeReady (index.js:784:18)
at invoke (index.js:262:14)
at m.flush (index.js:180:11)
at g.flush (index.js:334:19)
at z._end (index.js:762:32)
at _boundAutorunEnd (index.js:499:12)
And if I just use <template> directly, there’s no error. I don’t think using static template is valid here, so just using the template tag directly works.
I foolishly deleted the version I was testing and now I can’t get Nate’s most recent version to run
theme-initializer.gjs:18 Uncaught (in promise) ReferenceError: constid is not defined
at n.loadPosts (theme-initializer.gjs:18:10)
at new n (theme-initializer.gjs:12:10)
at h.createComponent (index.js:259:12)
at $.create (index.js:419:28)
at Object.evaluate (index.js:985:23)
at Object.evaluate (index.js:103:106)
at tr.evaluateSyscall (index.js:2873:20)
at tr.evaluateInner (index.js:2852:64)
at tr.evaluateOuter (index.js:2849:10)
at tH.next (index.js:4167:45)
at tH._execute (index.js:4157:21)
at tH.execute (index.js:4133:41)
at tq.sync (index.js:4194:120)
at tz.render (index-BCp6wOJU.js:4636:43)
at index-BCp6wOJU.js:4934:16
at eX (index.js:2414:7)
at tG._renderRoots (index-BCp6wOJU.js:4914:7)
at tG._renderRootsTransaction (index-BCp6wOJU.js:4962:12)
at tG._renderRoot (index-BCp6wOJU.js:4904:10)
at tG._appendDefinition (index-BCp6wOJU.js:4828:10)
at tG.appendOutletView (index-BCp6wOJU.js:4818:10)
at invoke (index.js:264:14)
at m.flush (index.js:180:11)
at g.flush (index.js:334:19)
at z._end (index.js:762:32)
at _boundAutorunEnd (index.js:499:12)
this very first version is the only one I can get to run
import { apiInitializer } from "discourse/lib/api";
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
class FirstPosts extends Component {
@tracked posts = [];
constructor() {
super(...arguments);
this.loadPosts();
}
async loadPosts() {
let topicIds = [98, 239]; // change to your topic IDs
let posts = [];
for (let id of topicIds) {
const res = await fetch(`/t/${id}.json`);
const data = await res.json();
if (data.post_stream && data.post_stream.posts.length > 0) {
posts.push(data.post_stream.posts[0]);
}
}
this.posts = posts;
}
<template>
{{#each this.posts as |post|}}
<div class="first-post-preview">
<h4>{{post.topic_title}}</h4>
{{{post.cooked}}}
</div>
{{/each}}
</template>;
}
export default apiInitializer((api) => {
api.renderInOutlet("above-main-container", FirstPosts);
});
I am trying to use the theme JS tab to do this
maybe I should switch to a theme on gitthub, is that where my limitation is?
I believe (in theme components and plugins) you can only include templates with that syntax in a standalone .gjs file as that suffix flags the interpreter to pre-compile it. Not sure how that affects the inbuilt online theme system.
Thank you for that advice, I am trying to do that now. Getting as far as I have has given me encouragement. Nate’s code above actually runs and puts the two topics on top. I will start a new topic with my theme idea and try to document what I learn. ask.discourse.org is absolutely amazing!