How to use MessageChannel with an iframe in Vuejs Template

299 Views Asked by At

We need to display data from an external site in an iframe while also being able to listen for events.

I can get the iframe to render with the url that is returned from the API. Where is am stuck is with eventHandlers and messaging.

Specifically:

  1. Should I define channel in data? Or as a computed property? Does it matter?
  2. The code snippet for sending "port2 into the iframe" on the callback of the iframe element - How can I reference this callback in my vue template?
  3. How do I actually use the channel.port1.onmessage snippet? I'm assuming this is listening to any messages sent FROM the iframe in port2. Is this where I would call different functions based on the event.data.handlerName that shows up?

Here is the API documentation:

Use the MessageChannel API to create a new channel. You’ll use the two ports connected to the channel to communicate between your application and the UX inside the iframe.

const channel = new MessageChannel();

Send port2 into the iframe embedding the UX using the onLoad callback of the <iframe> element:

iframe.addEventHandler(“load”, (event) => {
    iframe.contentWindow.postMessage("", "*", [channel.port2]);
});

Now that the embedded experience has received port2, listen to events from the iframe on port1, the port you retained earlier:

channel.port1.onmessage = (event) => {
    // check event.data.handlerName and event.data.eventType,
    // and handle messages sent from the embedded UX
};

Here is my template.

<template>
  <div class="dashboard">
    <div class="dashboard__container">
      <div class="dashboard__container--header">
        <h1>Contractors</h1>
      </div>
      <div class="dashboard__container--body">
        <iframe 
          :src="iframaData"
          id="frame"
          ></iframe>
      </div>
    </div>
  </div>
</template>


<script>
import { mapState } from 'vuex'
import firebase from 'firebase/app';

export default {
  name: 'accountPayroll',
  data: () => ({ 
    iframaData: null,
    channel: '',
  }),
  methods: {
    createComponentSession() {
      console.log('fetching')
      const createComponentSession = firebase.functions().httpsCallable('createComponentSession')
      createComponentSession({
        id: this.currentUser.uid
      })
      .then(result => {
        if (result && result.data && result.data.url) {
          this.iframaData = result.data.url
          console.log(result.data)
        }
      })
    },
    sendPort2() {
      this.iframe.addEventHandler(event => {
        this.iframe.contentWindow.postMessage("", "*", [this.channel.port2]);
      });
    },
    message() {
      this.channel.port1.onmessage = (event) => {
        // return event.data.handlerName == "ONBOARDING"
        console.log(event)
      };
    }
  },
  computed: {
    ...mapState(['currentUser', 'userProfile']),
    channel1() {
      return this.channel.port1;
    },
    channel2() {
      return this.channel.port2;
    },
    iframe() {
      return this.$el.querySelector("iframe")
    }
  },
  created() {
    this.channel = new MessageChannel()
    this.createComponentSession()
  },
  mounted() {
    this.sendPort2()
    this.message()
  },
  beforeDestroy () {
    this.iframaData = null;
    delete this.iframeData;
  }
}

</script>

Any help would be much appreciated. Thanks!

0

There are 0 best solutions below