Access tracked variables in VanillaJS?

I have this piece of code:

let iFrame = document.getElementById('oc-editor');
iFrame.addEventListener('load', function() {
  iFrame.contentWindow.postMessage({
    eventType: 'populateCode',
    language: "{{this.codeLang}}",
    files: [
      {
        "name": "file.{{this.codeLang}}",
        "content": "{{this.codeLang}}"
      }
    ]
  }, "*");
});

It changes the iframe which is in a DModal to include the code’s language and content. However, it tells me that iFrame is null, so it could not add addEventListener to it.
I’ve tried this:

<template>
  <DButton
    @translatedLabel="Show Modal"
    @action={{this.showModal}}
  />

  {{#if this.modalIsVisible}}
    <DModal @title="Code Compiler" @closeModal={{this.hideModal}}>
      <p>Code: {{this.getCode}}</p>
      <iframe
       frameBorder="0"
       height="450px"  
       src="https://onecompiler.com/embed/{{this.codeLang}}" 
       width="100%"
       id="oc-editor"
       title="OneCompiler Code Editor"
       listenToEvents="true">
      </iframe>
      <script>
        let iFrame = document.getElementById('oc-editor');
        iFrame.addEventListener('load', function() {
          iFrame.contentWindow.postMessage({
            eventType: 'populateCode',
            language: "{{this.codeLang}}",
            files: [
              {
                "name": "file.{{this.codeLang}}",
                "content": "{{this.codeLang}}"
              }
            ]
          }, "*");
        });
      </script>
    </DModal>
  {{/if}}
</template>

But that didn’t work as well. Is there a way I can do this?


Link to repo:

Looks like you’re working in gjs, so you can just use glimmer functions instead of trying to work around DOM rendering and race conditions. Add the glimmer {{on}} modifier with the iframe element and make your on loaded function fire on it.

@action
onIframeLoaded() {
...
}

...
<iframe {{on "load" this.onIframeLoaded}}
2 Likes

That… exists!? Wow, I’ll give it a shot.

Hmm… got this error:

Compile error: Error: /discourse/theme-9718/discourse/components/show-onecompiler: Parse error on line 18:
...   {{on "load" this.onIframeLoaded()}}>
-----------------------^
Expecting 'ID', got 'INVALID' (discourse/components/show-onecompiler.gjs)

Code:

@action
  onIframeLoaded() {
    let iFrame = document.getElementById('oc-editor');
    iFrame.contentWindow.postMessage({
      eventType: 'populateCode',
      language: "{{this.codeLang}}",
      files: [
        {
          "name": "file.{{this.codeLang}}",
          "content": "{{this.codeLang}}"
        }
      ]
    }, "*");
    return;
  }


  <template>
    <DButton
      @translatedLabel="Show Modal"
      @action={{this.showModal}}
    />

    {{#if this.modalIsVisible}}
      <DModal @title="Code Compiler" @closeModal={{this.hideModal}}>
        <p>Code: {{this.getCode}}</p>
        <iframe
          frameBorder="0"
          height="450px"  
          src="https://onecompiler.com/embed/{{this.codeLang}}" 
          width="100%"
          id="oc-editor"
          title="OneCompiler Code Editor"
          listenToEvents="true"
          {{on "load" this.onIframeLoaded()}}>
        </iframe>
      </DModal>
    {{/if}}
  </template>

Ah, I messed up my example. It should be {{on "load" this.onIframeLoaded}}, no parentheses, since it should be a reference to a function.

I’ve edited my reply.

3 Likes

Hmm… it says that Error: 74:13 error 'on' is not defined in ESLint. And the docs have no mention of an import because it’s a modifier.
I added event as a parameter to onIframeLoaded because the docs did that.

Add import { on } from "@ember/modifier"; and this should work.
It’s a good idea to look at the Discourse source code. It’s a good place to learn with existing code.

2 Likes

See also GitHub - discourse/all-the-plugins and GitHub - discourse/all-the-themes

3 Likes