Sub6Resources / flutter_html

A Flutter widget for rendering static html as Flutter widgets (Will render over 80 different html tags!)
https://pub.dev/packages/flutter_html
MIT License
1.8k stars 871 forks source link

[QUESTION] How to access DOM properly #868

Closed SeriousMonk closed 2 years ago

SeriousMonk commented 3 years ago

Hi, I'm currently implementing a payment gateway for my app. I need to create an empty div with an id. Then a js function is called and generates a layout inside that div.

I managed to implement it using HtmlElementView, but for some reason it forces me to specify a fixed height and make the content scrollable otherwise it expands to fill the screen vertically. So now my widget is the following:

// coverage:ignore-file
@JS()
library braintree_payment;

// ignore: avoid_web_libraries_in_flutter
import 'dart:html' as html;
import 'dart:ui' as ui;

import 'package:egomenu/generated/l10n.dart';
import 'package:egomenu/utilities/constants.dart';
import 'package:egomenu/utilities/responsive_config.dart';
import 'package:flutter/material.dart';
import 'package:flutter_braintree/flutter_braintree.dart';
// ignore: implementation_imports
import 'package:flutter_braintree/src/request.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:js/js.dart';
import 'package:js/js_util.dart';
import 'package:responsive_builder/responsive_builder.dart';

// EXTERNAL JAVASCRIPT ==========================================

@JS()
external void initBraintree(auth);

@JS()
external payment(String auth, bool pypalEnabled);

@JS()
external closeBraintreeDropin();

@JS()
external submitBraintreeDropin();

// ==============================================================
// FLUTTER BRAINTREE WEB ========================================
// ==============================================================

class BraintreeWidget extends StatefulWidget {
  BraintreeWidget();

  @override
  _BraintreeWidgetState createState() => _BraintreeWidgetState();

  Future<BraintreeDropInResult?> start(BuildContext context, BraintreeDropInRequest request) async {
    // create div with html embedded
    String htmlL = """   
        <div id="dropin-container"></div>
    """;
    var paymentDiv = html.DivElement()
      ..style.height = "auto"
      ..style.width = "auto"
      ..style.backgroundColor = "red"
      ..appendHtml(htmlL);

    // attach to payment container
    // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory('braintree-container', (int viewId) => paymentDiv);

    // show dialog
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return ResponsiveBuilder(
          builder: (context, sizingInformation){
            ResponsiveConfig _responsiveValues = ResponsiveConfig.wh(sizingInformation.deviceScreenType, 1, 0.5, 0.95, 0.5);
            return AlertDialog(
              scrollable: true,
              content: Container(
                width: MediaQuery.of(context).size.width * _responsiveValues.width,
                //height: MediaQuery.of(context).size.height * _responsiveValues.height,
                child: this
              ),
              actions: <Widget>[
                TextButton(
                  child: Text(
                      S.of(context).cancelText,
                      style: textButtonTextStyle.copyWith(color: Colors.grey)
                  ),
                  onPressed: () => submitBraintreeDropin(),
                ),
                TextButton(
                  child: Text(
                    S.of(context).addText,
                    style: textButtonTextStyle
                  ),
                  onPressed: () => submitBraintreeDropin(),
                )
              ],
            );
          },
        );
      }
    );

    // call js function
    var promise = payment(request.clientToken!, request.paypalRequest == null ? false : true);
    String? nonce = await promiseToFuture(promise);

    // close dialog
    Navigator.pop(context);

    ... other logic
  }
}

class _BraintreeWidgetState extends State<BraintreeWidget> {
  @override
  Widget build(BuildContext context) {
    return Html(data: """   
        <div id="dropin-container"></div>
    """);
    return HtmlElementView(
      viewType: 'braintree-container',
    );
  }
}

And this is the js function:

async function payment(auth, paypalEnabled) {
  return new Promise((resolve, reject) => {
    resolvePromise = resolve;
    rejectPromise = reject;

    var options = {
      authorization: auth,
      selector: '#dropin-container'
    };

    if(paypalEnabled) options['paypal'] = {
        flow: 'vault'
    }

    braintree.dropin.create(options, (errCreate, instance) => {
        if (errCreate) {
          console.log("Error", errCreate);
          return reject(errCreate);
        }

        braintreeInstance = instance;
    });
  });
}

However I get the following error:

DropinError: options.selector or options.container must reference a valid DOM node

How can I properly access the 'dropin-container' div in the DOM?

Kind Regards :) lionel-animals-to-follow-on-instagram-1568319926

erickok commented 3 years ago

Hi! I don't quite understand what you are trying to achieve here. flutter_html is to render bits of html, and certianly not tries to provide a DOM that you can modify dynamically. It can also not execute javascript and we won't implement that.

What problem are you trying to solve?