GithubHelp home page GithubHelp logo

fable.form's People

Contributors

amine-mejaouel avatar leolorenzoluis avatar mangelmaxime avatar mattgallagher92 avatar terencehinrichsen avatar zelenij avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fable.form's Issues

Add help policy

There should be a way to add detailed help/description to individual form fields

Add "onCancel" functionality

At the moment there is no way to explicitly abandon the form - i.e. I can't see how a "Cancel" button can be added. This is a standard usability feature. At the moment I'm stuck on the form page, and either have to put a button somewhere before/after it, or navigate away by the means of "back" navigation or using navbar, if there is one.

I'm sure I can add the necessary code myself - would you accept the PR if it's working?

Readonly feature

It would be nice to have the ability to render the form as readonly.

Such as if we have a property:

RenderMode = Review | Edit

...where if form is in "ReadOnly" mode, it would display "labels" instead of the regular "input" fields? (which would essentially be the same input fields with the "readonly" modifier, and a class to take away the border from the input field).

image

The purpose would be to be able to review the same data in the same layout that it was input but non-editable.

The form would be able to switch form edit <-> review on demand.

Add `IsLoading` to the field config

In a same way that a field can be disabled, I think adding IsLoading to the field config can make sense.

I am unsure if we should do it the field config level or if it should be at the Attributes level (per case by case).

I think slight in favour of doing it as the config level and if a type of field doesn't suppose loading then it can just ignore that property.

Doing it at the config level, imply that Fable.Form will have a Base.setLoading function in it like Base.disable.

Form plugins

First off, the "Form.reactComponentField" is great! That said, it would be awesome to be able to expand the type of fields that Fable Forms can support through the use of plugins/extensions that we can all build/publish. Again, the reactComponentField works great, but a rigid contract will guarantee consistency.

We'll be trying to build a couple of them using reactComponentField for now:

listview:
Screen Shot 2022-07-28 at 6 56 42 AM

checkbox group:
Screen Shot 2022-07-28 at 6 56 26 AM

Question: Max number of fields in form

I am busy setting up a simple, but long form..
The code compiles perfectly fine, but when I want to render the form i get:

Uncaught Error: Currying to more than 8-arity is not supported: 11
    at curry (Util.js?2ca6:569)
    at form (ReceivingForm.fs.js?39f6:115)
    at eval (ReceivingPage.fs.js?c5b2:55)
    at Enumerator_Seq.eval [as f] (Seq.js?8dfc:338)
    at Enumerator_Seq.GetEnumerator (Seq.js?8dfc:64)
    at getEnumerator (Util.js?2ca6:50)
    at Enumerator_FromFunctions$1.eval [as next] (Seq.js?8dfc:198)
    at Enumerator_FromFunctions$1.System.Collections.IEnumerator.MoveNext (Seq.js?8dfc:99)
    at Enumerator_FromFunctions$1.eval [as next] (Seq.js?8dfc:181)
    at Enumerator_FromFunctions$1.System.Collections.IEnumerator.MoveNext (Seq.js?8dfc:99)

Is it a restriction in the library? Does it only allow 8 fields in a form max due to the util?

How to run the examples

There doesn't appear to be a start script so 'npm start' doesn't run. Can you add some simple instructions to run the examples please.

Add missing Form.disable function

// Example of implementation
// To be splitted in the different package
module Form =

    module Base =

        open Fable.Form.Base

        let disable (form : Form<'Values, 'Output, 'Field>) : Form<'Values, 'Output, 'Field> =
            Form (
                fun values ->
                    let filled =
                        fill form values
                    {
                        Fields =
                            filled.Fields
                            |> List.map (fun filledField ->
                                { filledField with IsDisabled = true}
                            )
                        Result = filled.Result
                        IsEmpty = filled.IsEmpty
                    }
            )

    module Simple =

        open Fable.Form.Simple
        open Fable.Form.Base

        let disable =
            Base.disable

Should I remove the fsi files?

When writing Fable.Form I discovered the .fsi file feature of F#

I liked the fact that it made everything private by default, however I am wondering if this not confusing potential readers/contributors

It also makes the code navigation less friendly

Should I remove them?

Display error on submit

When the user submits the form with one or more invalid fields, these fields are rendered with an error. For short forms this is how the user gets the feedback about the errors. However, if the form is long, such invalid fields, while still rendered correctly, may be above the fold and therefore there is no visual feedback to the user that the form is invalid.

Is there a mechanism to get the information about the form being invalid in the current implementation? Either similar to the Success message mechanism or some other way that would allow one to render the warning near the submit button or react in some other way.

Offer non-immediate validation in Fable.Simple.Form

The current validation strategies offered in Fable.Form.Simple are ValidateOnBlur and ValidateOnSubmit. Based on their names, I assumed that they would only validate when a field is blurred or the form is submitted. However, the behaviour instead seems to be that validation is first triggered after blur/submit, but is then triggered after every subsequent change to a field. I would like an option that results in validation only being triggered on submit.

I propose that the following would be suitable cases for the Fable.Form.Simple.Form.View.Validation type:

  • ValidateImmediately (trigger validation after every field state change)
  • ValidateOnBlurThenImmediately (currently known as ValidateOnBlur)
  • ValidateOnBlurOnly (trigger only after blur, not while still focused on a field)
  • ValidateOnSubmitThenImmediately (currently known as ValidateOnSubmit)
  • ValidateOnSubmitOnly (trigger only when submitting, not before)

Another possible case could be ValidateOnSubmitThenOnBlur, but my guess is that that wouldn't be very popular.

ValidateOnBlur and ValidateOnSubmit could remain in the library for now, but be marked as deprecated, prompting users to swtich to the ...ThenImmediately case to preserve behaviour.

Assuming that you're happy with the design proposed above, I'd be happy to investigate the ValidateOnSubmitOnly case, and hopefully make a PR. The other cases could be left for other contributors (or not implemented at all if there's no demand).

Make Fable.Form.Simple renderer agnostic

Currently Fable.Form.Simple has a strong dependency on React.

It should be possible to remove this dependency so it could be used in any Elmish application even ones running on top of WPF.
And also allow people to use another view layer than React like Snabbdom for example

Fable.Form.Simple with pure HTML?

I'm trying to understand the code but I'm having a hard time groking it. Could you provide a sample on how to create like simple asHtml with no dependencies and just pure HTML? I'm trying to use Fable.Lit in this scenario.

Rework how error tracking is done

Currently Fable form is using the label of the field to keep track of their errors.

But I am not sure if this is the correct ways of doing it, I feel like we should explicitly ask the user for a unique ID and then have it provide the label of the field.

For example, this cause problem is you change how the checkbox is defined to accept either a string or a ReactElement for its "label"

type Attributres =
	| Text of string
	| ReactElement of ReactElement

Then in the case of ReactElement we don't have the needed information to store the key of the field error. We need to change it to ReactElement of string * ReactElement.

This could be seen as a specific but I think it just shows that we have a wrong design in the current way we consider the forms.

Rework the APIs which manipulate the form state

ATM to manipulate a Fable.Form.Simple.Form.View.Model state we have the following functions:

  • Form.View.setLoading

But if we want to set the state to Success, Error _ then we need to update the record directly:

{
    model with
        Form.State =
            Form.View.Success "You have been logged in successfully"
},
Cmd.none,

We also have the function Form.View.idle which allows to initial the form state to idle by providing the values.

This feels like something is missing and that we have inconsistencies in how these portion of API is designed.

Explore if Fable.Form can be used with React hooks

In theory, it should be possible to make Fable.Form works outside of Elmish.

The base package of Fable.Form don't have a dependency on Elmish only the view does to get access to Dispatch which is used to send the new form representation.

I think it should be possible to make Fable.Form support both Elmish and Hooks.

onSubmit payload

What is the reason why the onSubmit payload is not of the type Values? For example, if I have:

type Values =
    { Name : string
      Email : string }

and the two corresponding fields defined in the form, the onSubmit will be defined as let onSubmit name email = ....

Why use the list of fields here and not the Values type? Similar to the Value field function in the field record definition (e.g. Value = fun values -> values.Name).

I'm still struggling to understand how the library works internally so any insight into this part would be great. Thank you!

Module not found: Error: Can't resolve 'react' in 'C:\skeleton\.fable\Feliz.1.40.0'

Hi, I am trying to create a barebones Fable.Form Project with absolute minimal dependencies, nothing that feels like magic, and a scriptable repeatable process.

I am getting the following errors when I run npm start.

Here are the repo steps

dotnet new fable-empty -n skeleton
dotnet add package Fable.Form.Simple.bulma
dotnet new tool-manifest
dotnet tool install paket
dotnet tool restore
dotnet paket add Fable.Form.Simple

Then I over write App.fs with

module App
 
open Elmish
open Fable.Form.Simple
open Fable.Form.Simple.Bulma
 
type Values =
    {
        Email : string
        Password : string
        RememberMe : bool
    }
 
type Model =
    Form.View.Model<Values>
 
 
type Msg =
    // Used when a change occure in the form
    | FormChanged of Model
    // Used when the user submit the form
    | LogIn of string * string * bool
 
 
let init () =
    {
        Email = ""
        Password = ""
        RememberMe = false
    }
    |> Form.View.idle
    , Cmd.none
 
 
let update (msg : Msg) (model : Model) =
    match msg with
    // We received a new form model, store it
    | FormChanged newModel ->
        newModel
        , Cmd.none
 
    // The form has been submitted
    // Here, we have access to the value submitted from the from
    | LogIn (_email, _password, _rememberMe) ->
        // For this example, we just set a message in the Form view
        { model with
            State = Form.View.Success "You have been logged in successfully"
        }
        , Cmd.none
 
 
let form : Form.Form<Values, Msg> =
    let emailField =
        Form.textField
            {
                Parser =
                    fun value ->
                        if value.Contains("@") then
                            Ok value
                        else
                            Error "The e-mail adress must contain a '@' symbol"
                Value =
                    fun values -> values.Email
                Update =
                    fun newValue values ->
                        { values with Email = newValue }
                Error =
                    fun _ -> None
                Attributes =
                    {
                        Label = "Email"
                        Placeholder = "[email protected]"
                    }
            }
 
    let passwordField =
        Form.passwordField
            {
                Parser = Ok
                Value =
                    fun values -> values.Password
                Update =
                    fun newValue values ->
                        { values with Password = newValue }
                Error =
                    fun _ -> None
                Attributes =
                    {
                        Label = "Password"
                        Placeholder = "Your password"
                    }
            }
 
    let rememberMe =
        Form.checkboxField
            {
                Parser = Ok
                Value =
                    fun values -> values.RememberMe
                Update =
                    fun newValue values ->
                        { values with RememberMe = newValue }
                Error =
                    fun _ -> None
                Attributes =
                    {
                        Text = "Remember me"
                    }
            }
 
    let onSubmit =
        fun email password rememberMe ->
            LogIn (email, password, rememberMe)
 
    Form.succeed onSubmit
        |> Form.append emailField
        |> Form.append passwordField
        |> Form.append rememberMe
 
let view (model : Model) (dispatch : Dispatch<Msg>) =
    Form.View.asHtml
        {
            Dispatch = dispatch
            OnChange = FormChanged
            Action = "Sign in"
            Validation = Form.View.ValidateOnSubmit
        }
        form
        model

Then

npm install
npm start

And i get

ERROR in ./.fable/Feliz.1.40.0/Interop.fs
Module not found: Error: Can't resolve 'react' in 'C:\skeleton.fable\Feliz.1.40.0'
@ ./.fable/Feliz.1.40.0/Interop.fs 7:0-38 8:0-26 258:34-39 259:38-51
@ ./.fable/Fable.Form.Simple.Bulma.1.1.0/Form.fs
@ ./src/App.fs
@ ./src/App.fsproj
i 「wdm」: Failed to compile.
Error from chokidar (C:): Error: EBUSY: resource busy or locked, lstat 'C:\DumpStack.log.tmp'
Error from chokidar (C:): Error: EBUSY: resource busy or locked, lstat 'C:\hiberfil.sys'
Error from chokidar (C:): Error: EBUSY: resource busy or locked, lstat 'C:\pagefile.sys'
Error from chokidar (C:): Error: EBUSY: resource busy or locked, lstat 'C:\swapfile.sys'
Error from chokidar (C:\node_modules): Error: EBUSY: resource busy or locked, lstat 'C:\DumpStack.log.tmp'
Error from chokidar (C:\node_modules): Error: EBUSY: resource busy or locked, lstat 'C:\hiberfil.sys'
Error from chokidar (C:\node_modules): Error: EBUSY: resource busy or locked, lstat 'C:\pagefile.sys'
Error from chokidar (C:\node_modules): Error: EBUSY: resource busy or locked, lstat 'C:\swapfile.sys'

Assistance: Simple Form implementation

I am trying to publish a Material-UI implementation for Fable.Form.Simple. The project compiles and everything looks good, but when I add a reference to it from another project (via Nuget) I get:

client: C:/Users/Terence/Projects/Safe-Playground/src/Client/Index.fs(202,29): (210,47) error FSHARP: The type referenced 
through 'Fable.Form.Simple.Form.View.ViewConfig`2' is defined in an assembly that is not referenced. You must add a reference 
to assembly 'Fable.Form.Simple'. (code 74)

I have added the reference to Fable.Form.Simple in my paket.dependencies, even added an open to the top of both my fsi and fs file (compiler is complaining that it is not necessary), but I am not able to add the reference to the implementation.

I feel like a complete idiot for not seeing where I am missing the reference and what I am doing wrong, any advise - (even if you just tell me where to look please) would be highly appreciated!

Source
Nuget

Think about adding add `Base.disableWhen`

Signature would be

let disableWhen
        (condition: 'Values -> bool)
        (form: Form<'Values, 'A, 'Attributes>)
        : Form<'Values, 'A, 'Attributes>
        =
        Base.disableWhen condition form

I am unsure if we should add this helpers or if this would lead to bad practice in the library code.

Offer pipeline builders for Field Attributes

Currently, attributes are exposed using records only meaning that we need to provides all the properties all the time.

Attributes = {
	Label = "Order Value"
	Placeholder = "Order Value"
	HtmlAttributes = []
}

This is annoying because we need to provide information that we don't care about.

For example, if you have a DatePickerField you could have attributes looking like that:

type Attributes = {
	Label: string
	DisplayMode: DisplayMode
	ShouldDisableDate: System.DateTime -> bool
	ShouldDisableMonth: System.DateTime -> bool
	ShouldDisableYear: System.DateTime -> bool
}

Forcing the user to provide all the ShouldDisableXX functions, even when he don't want to disable any.

Exposing an alternative API would allow us to work around this problem:

  1. We could use classes to have optional arguments but discovery is not that great in IDE IHMO
  2. We could use pipeline builders, making discovering API easier
Form.datePickerField {
    Parser =
        fun value ->
            match value.SelectedDate with
            | Some date -> Ok date
            | None -> Error "This field is required"
    Value = _.CollectionDate
    Update =
        fun newValue values -> {
            values with
                CollectionDate = newValue
                // Reset the time slot when the date changes
                CollectionTimeSlot = ""
        }
    Error = fun _ -> None
    Attributes =
        DatePickerField.Attributes.create "Collection Date"
        |> DatePickerField.Attributes.withDisplayMode DatePickerField.DisplayMode.Default
        |> DatePickerField.Attributes.withShouldDisableDate (fun date ->
            timeSlots
            |> List.exists (fun slot -> Date.getDayKey slot.Start = Date.getDayKey date)
            |> not
        )
}
  1. Another solution is to use fluent API like I did in the past for Thoth.Elmish.FormBuilder old comparaison of the different style

Today, I think I lean more toward pipeline builders.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.