1

Update - Resolved

Somehow, this problem was happening due to toggling the visibility of the iFrame div on the parent website side of things, rather than any EventListener/State issue on the Flutter slide.


I'm following Flutter Web listen to Events posted through iFrame and trying to send a message from a parent website to a child Flutter app in an iFrame.

The message is working correctly and I can print the value inside the Flutter app; however, I can't call setState from my event listener successfully and use the message value elsewhere.

The website code is the same as in the link above. In my Flutter app:

class HomePageWidget extends StatefulWidget {
  const HomePageWidget({Key? key}) : super(key: key);

  @override
  _HomePageWidgetState createState() => _HomePageWidgetState();
}

class _HomePageWidgetState extends State<HomePageWidget> {
  String? messageValue;

  @override
  void initState() {
    html.window.addEventListener('message', listen, true);
    super.initState();
  }

  @override
  void dispose() {
    html.window.removeEventListener('message', listen, true);
    super.dispose();
  }

  void listen(html.Event event) {
    var data = (event as html.MessageEvent).data;
    final received = data['message'];

    // This works successfully.
    print(received);

    // This does not.
    setState(() {
      messageValue = received;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Text(messageValue ?? 'no message');
  }
}

I've verified that I'm receiving the message in my listen() method. I'm expecting to be able to call setState from my listen() method too; is there an issue with state scope this since it's being called from the stateful widget's init method?

ECS
  • 11
  • 2
  • setState(() { messageValue = received; print(messageValue); }); can you run this for me? does this show anything? – Rationalist Jun 16 '23 at 13:44
  • That prints the message value. If I create another method, `modifyMessage() => setState() { messageValue = 'hello'; });`, and call that from somewhere else, I get the expected state update and the UI rebuild. – ECS Jun 16 '23 at 13:53
  • do this WidgetsBinding.instance?.addPostFrameCallback((_) { setState(() { messageValue = received; }); }); don't forget to import `import 'package:flutter/widgets.dart';` tell me if it does not work – Rationalist Jun 16 '23 at 14:02
  • No luck there; as a side note, nothing inside `addPostFrameCallback((_) { ...` is called at all. – ECS Jun 16 '23 at 14:18
  • just try messageValue = received outside of setState() and try empty setState(() {}) to update UI. See if it works? – Mearaj Jun 17 '23 at 00:45
  • Unfortunately this doesn't work; the UI does not update. The value of `messageValue` doesn't get updated outside of the `listen` callback. I've tried a couple of other things, like moving the `addEventListener` to the build method, or having the callback modify a variable that has been passed into the widget rather than a property of the stateful widget itself, but I get the same issue. – ECS Jun 19 '23 at 11:10
  • @ECS, try this and let me know...Future(()=> { setState((){ messageValue = received; }) }); – Mearaj Jun 19 '23 at 11:16
  • I think it's updating the messageValue, but not re-rendering ui. Try the code from my previous comment. – Mearaj Jun 19 '23 at 11:27
  • Same problem. After adding some breakpoints, I can add that the `listen` method calls, updates the `messageValue` value, and `build()` is called, but it does not use the new value of `messageValue`. If I change the message to be an incremental counter that increases when 1) a new message is received, or 2) when a button in the UI is tapped, the state for the `listen` counter and the state for the button tap counter is maintained, but as two different values. And only the button tap callback updates the UI. Really odd! – ECS Jun 19 '23 at 12:21
  • Can you post the minimal code for the index.html file, that can reproduce this issue.? It will help a lot. – Mearaj Jun 19 '23 at 16:09
  • 1
    That's helpful - I created https://gist.github.com/eilzo/f9e22ae9dbbec8d7e46cf6550116016f as a light demo, and it works! So I need to work out how it's different to my app's setup. – ECS Jun 19 '23 at 17:12
  • Okay, solved! In my `index.html`, I had a button which, when tapped, called `customElements.define("flutter-app", FlutterApp);` and created the Flutter app div. If I remove that, and just have the Flutter app iFrame load from the start, it works... Very bizarre, considering that the iFrame app was receiving messages and able to log the values from it, but couldn't update its own internal state. – ECS Jun 19 '23 at 17:26
  • @ECS, I am glad it's resolved. Congrats. :) – Mearaj Jun 19 '23 at 17:30

0 Answers0