Skip to content

[web] use HtmlElement inside a Widget like HtmlElementView in Flutter Web #49634

Closed

Description

@mkiisoft

The official Flutter Web example not longer working on Flutter Channel Dev.

Link: https://github.com/flutter/flutter_web/blob/master/examples/html_platform_view/lib/main.dart

Example:

import 'dart:html';

import 'package:flutter_web_ui/ui.dart' as ui;

import 'package:flutter_web/material.dart';

void main() {
  ui.platformViewRegistry.registerViewFactory(
      'hello-world-html',
      (int viewId) => IFrameElement()
        ..width = '640'
        ..height = '360'
        ..src = 'https://www.youtube.com/embed/IyFZznAk69U'
        ..style.border = 'none');

  runApp(Directionality(
    textDirection: TextDirection.ltr,
    child: SizedBox(
      width: 640,
      height: 360,
      child: HtmlElementView(viewType: 'hello-world-html'),
    ),
  ));
}

Current PlatformViewsRegistry only has the method "getNextPlatformViewId" and not longer "registerViewFactory"

PlatformViewsRegistry - platform_views.dart:

/// The [PlatformViewsRegistry] responsible for generating unique identifiers for platform views.
final PlatformViewsRegistry platformViewsRegistry = PlatformViewsRegistry._instance();

/// A registry responsible for generating unique identifier for platform views.
///
/// A Flutter application has a single [PlatformViewsRegistry] which can be accesses
/// through the [platformViewsRegistry] getter.
class PlatformViewsRegistry {
  PlatformViewsRegistry._instance();

  // Always non-negative. The id value -1 is used in the accessibility bridge
  // to indicate the absence of a platform view.
  int _nextPlatformViewId = 0;

  /// Allocates a unique identifier for a platform view.
  ///
  /// A platform view identifier can refer to a platform view that was never created,
  /// a platform view that was disposed, or a platform view that is alive.
  ///
  /// Typically a platform view identifier is passed to a [PlatformView] widget
  /// which creates the platform view and manages its lifecycle.
  int getNextPlatformViewId() => _nextPlatformViewId++;
}

Flutter Doctor:

[✓] Flutter (Channel dev, v1.14.5, on Mac OS X 10.14.5 18F132, locale en-US)
    • Flutter version 1.14.5 at /Users/username/Documents/flutter
    • Framework revision 92cbaa3efe (5 days ago), 2020-01-24 05:43:01 +0100
    • Engine revision 439a21816e
    • Dart version 2.8.0 (build 2.8.0-dev.5.0 e84bea25df)

 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at /Users/username/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-29, build-tools 29.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.3.1, Build version 11C504
    • CocoaPods version 1.6.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 3.5)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 42.1.1
    • Dart plugin version 191.8593
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[✓] IntelliJ IDEA Community Edition (version 2019.1.3)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 36.1.4
    • Dart plugin version 191.7830

[✓] VS Code (version 1.38.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.4.1

[✓] Connected device (2 available)
    • Chrome     • chrome     • web-javascript • Google Chrome 79.0.3945.130
    • Web Server • web-server • web-javascript • Flutter Tools

• No issues found!

Notes:

There no current example/method to add HtmlElement into Widgets like HtmlElementView used to do thank to "registerViewFactory":

HtmlElementView(viewType:"string-key");

Activity

  1. changed the title [-][web]: platformViewsRegistry.registerViewFactory no longer exists[/-] [+][web] platformViewsRegistry.registerViewFactory no longer exists[/+] on Jan 28, 2020
  2. VladyslavBondarenko commented on Jan 28, 2020

    @VladyslavBondarenko

    Hi @mkiisoft
    As it said in readme:

    As of September 10, 2019, Flutter for web development has fully moved to https://github.com/flutter/flutter. To build web apps using Flutter use the standard Flutter SDK.

    Closing the issue since latest Flutter SDK doesn't imply use flutter_web, so flutter_web is not supposed to be compatible with it
    If you disagree please write in the comments and I will reopen it.
    Thank you

  3. mkiisoft commented on Jan 28, 2020

    @mkiisoft
    ContributorAuthor

    @VladyslavBondarenko I suggest to reopen the ticket and maybe rephrase it as we currently (AFAIK) don't have a way to use HtmlElement inside a Widget like HtmlElementView and that feature used to exists.

  4. changed the title [-][web] platformViewsRegistry.registerViewFactory no longer exists[/-] [+][web] use HtmlElement inside a Widget like HtmlElementView in Flutter Web[/+] on Jan 29, 2020
  5. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    c: new featureNothing broken; request for a new capability
    platform-webWeb applications specifically
    on Jan 29, 2020
  6. added this to the February 2020 milestone on Jan 30, 2020
  7. harryterkelsen commented on Jan 31, 2020

    @harryterkelsen
    Contributor

    @mkiisoft you can still use HtmlElement with HtmlElementView. See the video_player plugin for an example.

    The documentation for HtmlElementView should be improved with a code example of how to register an HTML element to use with it.

  8. thachnb85 commented on Feb 4, 2020

    @thachnb85

    Hi @hterkelsen Is there anyway to evaluate javascript inside the HtmlElementView? I'm trying to integrate the Paypal button (just bunch of html and js: https://developer.paypal.com/docs/checkout/#try-the-buttons) into flutter web app, by embedding them all into HtmlElementView, but the script doesn't work.

    Do you have any recommendation to run script and html at the same time? Thank you!

  9. datayeah commented on Feb 4, 2020

    @datayeah

    @hterkelsen the video_player example uses ui.platformViewRegistry which doesn't exist in the dart.ui package. At least in the (latest) flutter release i am working with: [✓] Flutter (Channel master, v1.14.7-pre.101, on Mac OS X 10.14.4

  10. thachnb85 commented on Feb 4, 2020

    @thachnb85

    @hterkelsen Hi Harry, I checked the method up above, I have to call document.getElementsByTagName('flt-platform-view'); to get that element, and add the new DivElement dynamically to that flt-platform-view's parent. But clicks event is not processed properly (no click event at dynamically rendered button inside the div), is there any way to get that click callback from dynamically rendered button?

  11. 25 remaining items

  12. srvstvnhl commented on Mar 5, 2021

    @srvstvnhl

    @SSVernekar Please have a look, I have mentioned with step which follows how the html values are being passing.

    Step:1
    `Future showEncountersWeb(BuildContext context, Map encounter) async {
    List html = htmlValues.reversed.toList();

    Navigator.push(context, MaterialPageRoute(builder: (context) => EncounterDetail(encounter["doctorName"],encounter["time"],html[encounter["index"]])));
    

    }`

    Step:2
    `class EncounterDetail extends StatefulWidget{
    String docName;
    String time;
    String value;
    EncounterDetail(this.docName,this.time,this.value);

    @OverRide
    _EncounterDetail createState() => _EncounterDetail(docName,time,value);
    }

    class _EncounterDetail extends State{
    String docName;
    String time;
    String value;
    _EncounterDetail(this.docName,this.time,this.value);

    String healthId;
    String consentStartDate;
    String consentEndDate;
    String consentRequestId;
    String consentExpiryDate;
    String consentRequestedDate;
    String status;
    Color statusColor;
    List hiTypes;

    OverlayEntry _overlayEntry;
    ..... rest of the code`

    Step: 3
    it is the same (encounterDetail )class where I am calling the IframView class which will have one particular value to render Padding( padding: EdgeInsets.only(top:40), child: IframeView(value), ), I am calling

    Step:4
    `class IframeView extends StatefulWidget { String url;

    IframeView(this.url);

    @OverRide
    _IframeViewState createState() => _IframeViewState(url);
    }

    class _IframeViewState extends State {
    String url;
    _IframeViewState(this.url);
    final html.IFrameElement _iframeElement = html.IFrameElement();

    Widget _iframeWidget;

    @OverRide
    void initState() {
    _iframeElement.height = '500';
    _iframeElement.width = '500';
    _iframeElement.srcdoc = widget.url;
    _iframeElement.style.border = 'none';

    ui.platformViewRegistry.registerViewFactory('iframeElement', (int viewId) {
    return _iframeElement;
    });

    _iframeWidget = HtmlElementView(
    key: UniqueKey(),
    viewType: 'iframeElement',
    );

    super.initState();
    }

    @OverRide
    void didUpdateWidget(IframeView oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("from did update widget");
    print(_iframeElement.srcdoc);
    _iframeElement.srcdoc = widget.url;
    }

    @OverRide
    Widget build(BuildContext context) {
    return Container(
    margin: EdgeInsets.only(top: 50),
    child: _iframeWidget,
    );
    }
    }`

  13. SSVernekar commented on Mar 5, 2021

    @SSVernekar

    Step:1
    `Future showEncountersWeb(BuildContext context, Map encounter) async {
    List html = htmlValues.reversed.toList();

    Navigator.push(context, MaterialPageRoute(builder: (context) => EncounterDetail(encounter["doctorName"],encounter["time"],html[encounter["index"]])));
    }`

    Step:2
    `class EncounterDetail extends StatefulWidget{
    String docName;
    String time;
    String value;
    EncounterDetail(this.docName,this.time,this.value);

    @OverRide
    _EncounterDetail createState() => _EncounterDetail(docName,time,value);
    }

    class _EncounterDetail extends State{
    String docName;
    String time;
    String value;
    _EncounterDetail(this.docName,this.time,this.value);

    String healthId;
    String consentStartDate;
    String consentEndDate;
    String consentRequestId;
    String consentExpiryDate;
    String consentRequestedDate;
    String status;
    Color statusColor;
    List hiTypes;
    final html.IFrameElement _iframeElement = html.IFrameElement();

    Widget _iframeWidget;

    String url;

    @OverRide
    void initState() {
    _iframeElement.height = '500';
    _iframeElement.width = '500';
    _iframeElement.srcdoc = widget.url;
    _iframeElement.style.border = 'none';

    ui.platformViewRegistry.registerViewFactory('iframeElement', (int viewId) {
    return _iframeElement;
    });

    _iframeWidget = HtmlElementView(
    key: UniqueKey(),
    viewType: 'iframeElement',
    );

    super.initState();
    }

    OverlayEntry _overlayEntry;
    ..... rest of the code`
    Padding( padding: EdgeInsets.only(top:40), child: _iframeWidget )

    }

  14. SSVernekar commented on Mar 5, 2021

    @SSVernekar

    @srvstvnhl try the above code i think it will work

  15. deusoz commented on Aug 26, 2021

    @deusoz

    HERE is code using Image Element for rendering with HtmlElementView. from a newbie Flutter dabbler:

    first to undo ui.platformView... error in VS, add analysis_options.yaml

    analyzer:
      errors:
        undefined_prefixed_name: ignore
    

    //Class to render images with set height / width...

    import 'dart:html';
    import 'dart:ui' as ui;
    import 'dart:math';
    
    import 'package:flutter/material.dart';
    
    class RenderLinkImage extends StatefulWidget {
      final src;
    
      RenderLinkImage({this.src});
    
      @override
      _RenderLinkImageState createState() => _RenderLinkImageState();
    }
    
    class _RenderLinkImageState extends State<RenderLinkImage> {
      var randomString = getRandomString(17);
      @override
      Widget build(BuildContext context) {
        ui.platformViewRegistry.registerViewFactory(
          "link_image_instance$randomString",
          (int viewId) {
            ImageElement element = ImageElement()
              ..src = widget.src
              ..style.border = "none";
            element.height = 103;
            element.width = 177;
            return element;
          },
        );
    
        return SizedBox(
          height: 103,
          width: 177,
          child: HtmlElementView(
            viewType: "link_image_instance$randomString",
          ),
        );
      }
    
      static getRandomString(len) {
        var r = Random();
        const _chars =
            'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
        return List.generate(len, (index) => _chars[r.nextInt(_chars.length)])
            .join();
      }
    }
    

    // image is url string to web image, somewhere else you imported class..

    ...
    child: RenderLinkImage(src: image)),
    
  16. ditman commented on Aug 27, 2021

    @ditman
    Member

    This issue is getting a little bit unwieldy, and I feel it's been solved (HtmlElements can be used inside HtmlElementViews, external JavaScript can see those elements, and a bunch of other issues have been resolved).

    Is there anything actionable left to do in this issue?

    I think the biggest problem (and I'd like to create a new issue for that, so we can prioritize it accordingly) is closer to the original request:

    • ui.platformViewRegistry (from dart:ui) is a web-only API, and the analyzer complains when attempting to use that "non-existent" API.

    This is a bigger problem than HtmlElementViews, however, because dart:ui is exposing a very large API, and it's not entirely clear to me how (or where) to extract that API so it's usable in apps and plugins.

    Is there anything else missing, before I close this issue in favor of removing web-only APIs from dart:ui?

  17. ditman commented on Mar 23, 2024

    @ditman
    Member

    The new documentation is already visible in the main branch API docs:

  18. github-actions commented on Apr 6, 2024

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  19. locked as resolved and limited conversation to collaborators on Apr 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projectc: new featureNothing broken; request for a new capabilityframeworkflutter/packages/flutter repository. See also f: labels.platform-webWeb applications specificallyteam-webOwned by Web platform teamtriaged-webTriaged by Web platform team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions