Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJs with Iframe events and changes handling

I have ReactJs Component which includes an iframe. That iframe is used to do some job and after it finishes it has callback to Success or Error pages. In my chrome browser, network tab I can see the requests and responses. I want to be able to handle those callbacks in frontend somehow, did any of you met this type of problem?

My project is MVC and I do not have Success and Error actions in my controllers, it is an single page application with React.

UPDATE my whole iframe looks like this

This iframe is third-party integrations which does a callback on success and error to static URL: host/controller/success and host/controller/error

My mission is to catch when this happens in React, I hope this is possible somehow, I was trying to listen to 'message' event, but might be that I am doing anything incorrect.

Any suggestions are appreciated

like image 305
GrandaS Avatar asked Jan 16 '18 08:01

GrandaS


People also ask

Can I use iframe in React JS?

In React, developers use iframes to create either a sandboxed component or an application that is isolated from its parent component. In an iframe, when a piece of content is embedded from an external source, it is completely controlled by the source instead of the website it is embedded in.

How do I pass a component in iframe React?

We can simply use the ReactDOMServer. renderToString() to convert a react component to string and then set it to srcDoc attribute of iframe. The js event handlers like onClick don't work with this solution.

How do I show iframe in React?

import React from "react"; import ReactDOM from "react-dom"; function App() { return ( <div className="App"> <h1>Iframe Demo</h1> <Iframe iframe={iframe} />, </div> ); } const rootElement = document. getElementById("root"); ReactDOM. render(<App />, rootElement);

How do you know if an iframe is loaded React?

To detect when the iFrame has finished loading, we need to add an event listener to the iFrame, and we need to return the removeEventListener function to remove the event listener if our component unmounts.


1 Answers

If you own the frame content you should use window postmessage to send content back to your page. https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

If you are using MVC you can potentially add the postmessage listeners to your controller and send them to reply back to the view.

Update

I've created a sample of what I was talking about.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
</head>
<body>
  <div id="app"></div>
  <script src="./main.js" type="text/babel"></script>
</body>
</html>

iframe.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script>
    window.top.postMessage(
      JSON.stringify({
        error: false,
        message: 'Here we go'
      }),
      '*'
    );
  </script>
</body>
</html>

main.js

// React controller used to load the iframe
class Loading extends React.Component {
  render() {
    return (
      <div>
        Waiting on iframe
        <iframe src={this.props.iframeUrl}></iframe>
      </div>
    );
  }
}

// React controller used after iframe postmessage
class Complete extends React.Component {
  render() {
    return (
      <div>
        iFrame postmessage got me here
      </div>
    );
  }
}

// Sample of controller
class Controller {
  constructor() {
    this.loading = true;
    this.onMessageReceived = this.onMessageReceived.bind(this);
    this.bindEvents();
    this.render();
  }

  bindEvents() {
    window.addEventListener("message", this.onMessageReceived, false);
  }

  onMessageReceived(event) {
    var data = JSON.parse(event.data);
    console.log(data);
    this.loading = false;
    this.render()
  }

  render() {
    if (this.loading){
      ReactDOM.render(
        <Loading iframeUrl="./iframe.html" />,
        document.getElementById('app')
      );
    } else {
      ReactDOM.render(
        <Complete />,
        document.getElementById('app')
      );
    }
  }
}

// Run the controller
new Controller();
like image 117
Joao Lopes Avatar answered Oct 18 '22 15:10

Joao Lopes