6

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

K V
  • 578
  • 2
  • 5
  • 24
  • Just adding that if you do not have access to the iframe, this is a related [question](https://stackoverflow.com/questions/15273042/catch-error-if-iframe-src-fails-to-load-error-refused-to-display-http-ww) – aug Jan 29 '19 at 19:11

1 Answers1

8

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();
Joao Lopes
  • 936
  • 5
  • 9
  • Well I do not own the content of iframe, all I do is add tag in my React component. Can you add more information about the second option - listeners? – K V Jan 16 '18 at 08:27
  • I can't really add a code example now because I'm on the phone. Will share an example soon – Joao Lopes Jan 16 '18 at 08:33
  • 1
    Would really appreciate that, please – K V Jan 16 '18 at 08:38
  • I've edited the original answer with the update. Let me know if that helps. – Joao Lopes Jan 16 '18 at 10:23
  • Oh wow. Sorry @GrandaS I've only now realised that you said you **don't** own the content of the iframe. Ok, how does the iframe communicate back to the iframe then? Can you share the iframe code? – Joao Lopes Jan 16 '18 at 10:27
  • 1
    I updated my question, by the way, thanks for your code sample, but this does not fit my situation – K V Jan 16 '18 at 11:03
  • @GrandaS is there any way to look at the code? Or a sample of the iframe code? – Joao Lopes Jan 16 '18 at 11:06
  • Well, no, I cannot see the code except the Inspect on Dev Tools (F12 in chrome). However, it appeared that one of us knew another trick with that specific integration and we could manage to change callback urls, so I just changed it to be hash url and that was enough in my case. But it would be nice to solve this problem in my question – K V Jan 16 '18 at 13:57
  • you don't need to `JSON.stringify` and `JSON.parse` the objects. as long as they are serializable they are sent as objects and you can treat them normally. Example: `window.top.postMessage({error: false, message: 'Here we go'})` – Soldeplata Saketos Dec 10 '21 at 07:30
  • I had to use `window.parent?.postMessage` instead of `window.top` – Taku Jun 07 '22 at 23:17