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.76k stars 815 forks source link

Support for <input /> tag is badly needed! #599

Closed misici234 closed 3 years ago

erickok commented 3 years ago

Could you explain your use case?

ryan-berger commented 3 years ago

I'm going to say hard pass on this tag @erickok . I can't really think of a good reason to implement this, and it seems extremely antithetical to the library's goals/philosophy of just "rendering".

misici234 commented 3 years ago

I've been developing a mobile app for months to support the work of the doctors and other medical staff. My company already has a mature web application to support a lot of needs of our clients and they want to offer a subset of web functionalities in the mobile app. One of them is a patient's progress notes which they can enter in the web application as HTML documents with many tags including input tag. I don't know why the medical staff need input tags but I know they use them. The web progress notes come to my mobile app via web APIs and I have to be able to display them properly.

erickok commented 3 years ago

I tend to agree with @ryan-berger here. There should be a very clear use-case and even then I doubt whether we can get a satisfactory implementation, especially given there is no javascript. How much can you achieve in a basic html form these days?

Of couse one can always implement these themselves with our customRender API. Just claim support for the 'input' tag and return an TextField or Button or whatever element you need.

misici234 commented 3 years ago

What is difference between intput, div, td tags? They are all commonly used HTML tags. I don't understand why you have a selective approach. Our customers are looking for a solution and they want to see their input elements rendered properly. If you don't want to do it then show us a working example of how we can do it using customRender API.

erickok commented 3 years ago

We could render them, but that's not going to help you very much by itself. For input tags to be useful you also want to do something with those buttons, text fields or whatever widget is bound to the input tag. At least you want to handle clicks and capture the text input via controllers. Likely you want to verify the input for validity. That's all much more than simply rendering, how all the other tags are supported, and therefore something different than what we currently do. How do we manage state now, or allow injection of text controllers. How do we attach the button click listeners? Do you expect the form data to be urlencoded and send via post to whatever the form tag species? Probably not.

misici234 commented 3 years ago

No, I don't want to do anything with input tags. Just to display them in read-only mode like all other tags (from your example). If a user ticked a checkbox then render it as the ticked checkbox and nothing else. No Javascript, no validation, nothing except rendering it properly. Please keep in mind, you support read-only mode. There are other widgets, called HTML editors, which are capable of producing HTML content but that's another story.

tneotia commented 3 years ago

I agree with @erickok here regarding using customRender. I understand this library is read-only but <input> by nature is meant to be a write-based tag. What good is it to show a textfield or a button when you can't do anything with it? Imho it would confuse the user because they can't click on it, modify it, etc.

If you really need it, you can do this:

customRender: {
            "input": (context, child) {
              return your_child //a textfield, button, etc...
            }
          },

I can't really give a super comprehensive example because I don't quite understand how you would render your input tags in a read-only format. You can use context.tree.<parameter> to get specific details about the input tag being passed to the customRender and return a widget accordingly.

erickok commented 3 years ago

Here is a simple example on how to render form fields using customRender:

      Html(
        data: """
          <form action="/action_page.php">
            <label for="fname">First name:</label><br>
            <input type="text" id="fname" name="fname" value="John"><br>
            <label for="lname">Last name:</label><br>
            <input type="text" id="lname" name="lname" value="Doe"><br><br>
            <label for="doctor">Is a doctor:</label><br>
            <input type="checkbox" id="doctor" name="doctor" value="Doctor" checked="checked"><br><br>
            <input type="submit" value="Submit">
          </form> 
        """,
        style: {
          "ul": Style(listStyleType: ListStyleType.DISC, markerContent: "X"),
        },
        customRender: {
          "form": (context, child) {
            return Column(
                children: context.tree.element!.children
                    .map((e) => Text.rich(context.parser.parseTree(context, parseStyledElement(e, []))))
                    .toList());
          },
          "label": (context, child) {
            return Text(context.tree.element!.text);
          },
          "input": (context, child) {
            switch (context.tree.element!.attributes["type"]) {
              case "text":
                return TextField(controller: TextEditingController(text: context.tree.element!.attributes["value"]));
              case "checkbox":
                return Checkbox(value: context.tree.element!.attributes["checked"] == "checked", onChanged: null);
              default:
                return Container();
            }
          },
        },
      )

Screenshot 2021-04-09 at 09 57 14

Unless there is much, much more interest in this feature, I think using a customRender gives enough flexibility for a use-case like yours to say we do not add any specific support for form/input/label tags.

gzlock commented 3 years ago

@erickok Not work in the version

Flutter 2.0.6 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 1d9032c7e1 • 2021-04-29 17:37:58 -0700
Engine • revision 05e680e202
Tools • Dart 2.12.3

flutter_html ^2.0.0-nullsafety.1

Your code render an empty widget.

tneotia commented 3 years ago

@gzlock what is your HTML code?

gzlock commented 3 years ago

@gzlock what is your HTML code?

Copy from the @erickok example code.

erickok commented 3 years ago

@gzlock Did you add the tags to the include list? Since flutter_html 2.0.0 you need to add tags (that we don't support out-of-the-box) explicitly.

tagsList: Html.tags..addAll(["form", "label", "input"]),

So the full example becomes:

    Html(
          data: """
          <form action="/action_page.php">
            <label for="fname">First name:</label><br>
            <input type="text" id="fname" name="fname" value="John"><br>
            <label for="lname">Last name:</label><br>
            <input type="text" id="lname" name="lname" value="Doe"><br><br>
            <label for="doctor">Is a doctor:</label><br>
            <input type="checkbox" id="doctor" name="doctor" value="Doctor" checked="checked"><br><br>
            <input type="submit" value="Submit">
          </form> 
        """,
          tagsList: Html.tags..addAll(["form", "label", "input"]),
          style: {
            "ul": Style(listStyleType: ListStyleType.DISC, markerContent: "X"),
          },
          customRender: {
            "form": (context, child) {
              return Column(
                  children: context.tree.element!.children
                      .map((e) => Text.rich(context.parser.parseTree(context, parseStyledElement(e, []))))
                      .toList());
            },
            "label": (context, child) {
              return Text(context.tree.element!.text);
            },
            "input": (context, child) {
              switch (context.tree.element!.attributes["type"]) {
                case "text":
                  return TextField(controller: TextEditingController(text: context.tree.element!.attributes["value"]));
                case "checkbox":
                  return Checkbox(value: context.tree.element!.attributes["checked"] == "checked", onChanged: null);
                default:
                  return Container();
              }
            },
          },
        )
sathya4code commented 2 years ago

Hi @erickok,

How do we show the Radio buttons in custom renders. I tried but the radio selection not updating if I click on another radio button in same group.

erickok commented 2 years ago

That implementation is up to you, but you can continue my example for radio buttons or any other type of input. You have to manage any state yourself of course. This isn't something we support out of the box.

sathya4code commented 2 years ago

That implementation is up to you, but you can continue my example for radio buttons or any other type of input. You have to manage any state yourself of course. This isn't something we support out of the box.

Hi @erickok ,

Thanks for your response. I have done it already.