Acesso a variáveis rastreadas em VanillaJS?

{“translation”: "Eu tenho esse trecho de código:

let iFrame = document.getElementById('oc-editor');

if (iFrame) {
  iFrame.addEventListener('load', function() {
    iFrame.contentWindow.postMessage({
      eventType: 'populateCode',
      language: "{{this.codeLang}}",
      files: [
        {
          "name": "file.{{this.codeLang}}",
          "content": "{{this.codeLang}}"
        }
      ]
    }, "*");
  });
} else {
  // Pode ser necessário esperar o iframe ser carregado dinamicamente.
  // Uma abordagem é usar um MutationObserver ou um intervalo de teste.
}

O problema de iFrame ser null geralmente ocorre porque o script é executado antes do iframe estar presente no DOM. Para resolver isso, garanta que seu código que acessa o iframe seja executado após o carregamento completo do DOM ou após a renderização do iframe.

Se o iframe é renderizado condicionalmente (por exemplo, dentro de um if ou de uma template condicional), você pode precisar colocar seu código dentro de um método que seja chamado somente após o iframe estar na página, ou usar um setTimeout ou um MutationObserver para esperar até que o iframe exista.

Exemplo usando setTimeout:

setTimeout(function() {
  let iFrame = document.getElementById('oc-editor');
  if (iFrame) {
    iFrame.addEventListener('load', function() {
      iFrame.contentWindow.postMessage({
        eventType: 'populateCode',
        language: "{{this.codeLang}}",
        files: [
          {
            "name": "file.{{this.codeLang}}",
            "content": "{{this.codeLang}}"
          }
        ]
      }, "*");
    });
  }
}, 1000); // Espera 1 segundo para o iframe ser carregado

Ou, se possível, adicione seu script dentro do evento onload do iframe no HTML:

<iframe id="oc-editor" ... onload="initializePostMessage()"></iframe>
<script>
function initializePostMessage() {
  let iFrame = document.getElementById('oc-editor');
  iFrame.contentWindow.postMessage({
    eventType: 'populateCode',
    language: "{{this.codeLang}}",
    files: [
      {
        "name": "file.{{this.codeLang}}",
        "content": "{{this.codeLang}}"
      }
    ]
  }, "*");
}
</script>

Resumindo, o ponto importante é garantir que o iframe exista no DOM antes de tentar acessá-lo e registrar o evento load. Você também pode verificar se a API do iframe permite carregar e manipular o conteúdo como esperado, considerando políticas de CORS e sandbox.

Para mais detalhes ou uma implementação mais específica, recomendo verificar o ciclo de vida do seu framework ou tecnologia que está usando, assim como o momento exato em que o iframe fica disponível no DOM."}

Parece que você está trabalhando em gjs, então pode usar funções do glimmer em vez de tentar contornar a renderização do DOM e as condições de corrida. Adicione o modificador {{on}} do glimmer com o elemento iframe e faça sua função on loaded ser acionada nele.

@action
onIframeLoaded() {
...
}

...

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

Isso… existe!? Uau, vou tentar.

Hmm… recebi este erro:

Erro de compilação: Erro: /discourse/theme-9718/discourse/components/show-onecompiler: Erro de análise na linha 18:
...   {{on "load" this.onIframeLoaded()}}>
-----------------------^
Esperado 'ID', encontrado 'INVALID' (discourse/components/show-onecompiler.gjs)

Código:

@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="Mostrar Modal"
      @action={{this.showModal}}
    />

    {{#if this.modalIsVisible}}
      <DModal @title="Compilador de Código" @closeModal={{this.hideModal}}>
        <p>Código: {{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, eu errei meu exemplo. Deveria ser {{on \"load\" this.onIframeLoaded}}, sem parênteses, já que deve ser uma referência a uma função.

Editei minha resposta.

3 curtidas

Hmm… diz que Error: 74:13 error 'on' is not defined no ESLint. E a documentação não menciona uma importação porque é um modificador.
Adicionei event como parâmetro a onIframeLoaded porque a documentação fez isso.

Adicione import { on } from \"@ember/modifier\"; e isso deve funcionar.
É uma boa ideia olhar o código fonte do Discourse. É um bom lugar para aprender com código existente.

2 curtidas

Veja também GitHub - discourse/all-the-plugins e GitHub - discourse/all-the-themes

3 curtidas