MangelMaxime / Fable.Form

https://mangelmaxime.github.io/Fable.Form/
Other
54 stars 10 forks source link

Explore if Fable.Form can be used with React hooks #21

Open MangelMaxime opened 3 years ago

MangelMaxime commented 3 years ago

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.

Dewald844 commented 1 year ago

@MangelMaxime

I am playing around with Fable form trying to implement it with only React .

I managed to use React.useReducer as a update function which also gives me a Dispatch , only thing is that an update function used by useReducer needs to be pure so no Cmd commands after changing the model.

This is what i have sofar

   type Values = {
      Email : string
      Password : string
      RememberMe : bool
   }

   type Model = Form.View.Model<Values>

   type Message =
      | FormChanged of Model
      | LogIn of string * string * bool

   let evolve (model : Model) = function
      | FormChanged newModel -> newModel
      | LogIn (email, password, rememberMe) ->
         { model with State = Form.View.Success "You have logged in successfully" }

   let initialState () =
      {
         Email = ""
         Password = ""
         RememberMe = false
      }
      |> Form.View.idle

   let form =

      let emailField =
         Form.textField {
               Parser = fun v ->
                  if v.Contains("@") then Ok v
                  else Error "Invalid email address, Email address must contain a @ symbol"
               Value = fun v -> v.Email
               Update = fun newValue values -> { values with Email = newValue }
               Error = fun _ -> None
               Attributes = {
                  Label = "Email"
                  Placeholder = "Enter your email address"
                  HtmlAttributes = [  ]
               }
            }

      let passwordField =
         Form.passwordField {
            Parser = Ok
            Value = fun v -> v.Password
            Update = fun newValue values -> { values with Password = newValue }
            Error = fun _ -> None
            Attributes = {
               Label = "Password"
               Placeholder = "Enter your password"
               HtmlAttributes = [ prop.className "w" ]
            }
         }

      let rememberMe =
         Form.checkboxField {
            Parser = Ok
            Value = fun v -> v.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

   type Component =

      [<ReactComponent>]
      static member LogInForm () =

         let model, dispatch = React.useReducer (evolve, initialState ())

         Form.View.asHtml
            {
               Dispatch = dispatch
               OnChange = FormChanged
               Action = Form.View.Action.SubmitOnly "Sign in"
               Validation = Form.View.ValidateOnSubmit
            }
            form
            model
MangelMaxime commented 1 year ago

@Dewald844

Hello, thank you for the example, this is plus to have for people who want to avoid to use useElmish hooks.

My idea is to go one step farther and remove Elmish as a dependency of Fable.Form. This will require a few changes internally and to the exposed API but I hope to be able to focus on it soon once I am done upgrading another OSS project of mine.