Giter Site home page Giter Site logo

hecrj / composable-form Goto Github PK

View Code? Open in Web Editor NEW
201.0 12.0 20.0 869 KB

Build type-safe composable forms in Elm

Home Page: http://package.elm-lang.org/packages/hecrj/composable-form/latest

License: BSD 3-Clause "New" or "Revised" License

Elm 100.00%
elm type-safe composable form forms form-validation

composable-form's People

Contributors

andys8 avatar dependabot[bot] avatar hecrj avatar laserpants avatar mattdb avatar russelldavies avatar stephenreddek 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  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  avatar  avatar  avatar  avatar

composable-form's Issues

Update documentation

Most of the examples in the documentation are missing the new error attribute and need to be updated.

Additionally, we should explain the new error attribute in Form and clarify the fields property in Form.fill.

Question about custom views and fields

I'm creating an in browser http client with elm using the composable form package.

I was wondering how you picture doing something like a list field with an add and remove button for dynamic fields.

Currently I'm just creating that field within normal elm and adding it when submitting the composable form.

The pattern is something like this.

Thanks for your time!

Unable to select radio fields

Using Form.View.asHtml to render multiple radio buttons using Form.radioField, I have noticed that the options are displayed as expected, however they are unselectable.

Looking at the HTML generated I can see that the whole field is placed into a label, however multiple radio buttons are put into the label. As a result the browser always selects the first option regardless of where clicked.

<label class="elm-form-field">
    <div class="elm-form-label">Status</div>
    <fieldset>
        <div class="elm-form-label">
            <input name="Status" value="open" type="radio">
          	Open
      	</div>
        <div class="elm-form-label">
            <input name="Status" value="closed" type="radio">
          	Closed
      	</div>
    </fieldset>
</label>

Rolling back to version 4.0.1 fixes this as the following html is generated:

<div class="elm-form-field">
    <label>Status</label>
    <fieldset>
        <label><input name="Status" value="open" type="radio">open</label>
        <label><input name="Status" value="closed" type="radio">closed</label>
    </fieldset>
</div>

I believe the 4.0.1 HTML to be correct. In addition it was likely the fix in #13 that caused the break (sorry!)

Also, to nitpick, semantically it would make more sense for the elements with class "elm-form-label" should probably be a label instead of a div. I understand you're trying to keep the API simple without an "id" attribute though which I would agree is more valuable.

how to update a field value by another field value?

please tell me how to write code?

[scenario]
There are two form fields, zip field and address field.
User input for zip field, and access to server to get address.(HTTP GET)
And update address field value that server response value.

Status of composable-form?

Hi - composable-form looks great. I see that it hasn't been updated in a long while, and there are outstanding issues and a PR.

Is the project no longer maintained? If its deprecated in favor of something else, it would be great to have that in the Readme. Or if its in a "it works, but its not being maintained now" state, that would be great to know too.

Thanks!

Best way to render server side errors

Sometimes complex validations are being performed on the backend. Those errors are sent back to the frontend and stored, in my case, as a Dict String (List String) where the key is the field, and the list of strings is a list of validation errors for that field.

I've been reading several times the source code & the documentation but I can't find a good way to add the errors to the form.

I have a custom form view based on https://github.com/hecrj/composable-form/blob/master/examples/src/Form/View/Ui.elm and I thought about passing the errors to the layout as a first argument:

layout : Dict String (List String) -> ViewConfig values msg -> Form values msg -> Model values -> Element msg

send those errors to every field, for example for the number field :

, numberField = numberField serverErrors

and change numberField to:

numberField : Dict String -> (List String) -> NumberFieldConfig msg -> Element msg

And in that function maybe merge the serverErrors into error before showing it.

Isn't this too complex? Am I missing something? Could be useful to create a addErrorToField function somewhere?

no custom attributes?

I need some custom attributes. data-test-id or id or name for e2e tests, and autocomplete to let browsers properly fill out login/signup forms.

I've been using Form.View.custom so far, with CustomConfig and it works out for styling (bootstrap in my case). However, TextFieldConfig etc have only label and placeholder hardcoded into their attributes.

I am kind of lost here. Did I completely miss something?
Is this simply not possible without a PR?
Or should I start by copypasting the whole of Form.View.custom and everything "under it"?

Ability to add label to group

There are some times when a set of fields are related. It'd be cool if a label could be added to Form.group similar to hos Form.listworks.

Is is possible to isolate rendering from validation?

Hi,

I really like your approach of using a JSON decoder to validate the forms on the view events, but adding form rendering into the mixture does not fit my needs. Designs are to complex. Is it possible to have validation that I plug into my own forms?

Thanks!

label for=

This is a great library, thank you for making forms simple!

One thing that has come up is that the asHtml function doesn't add an id to the input nor a for attribute on the label. Could this be added in? Form.Base.TextField.Attributes seems to be the place to specify it.

select[multiple] and/or a checkbox representation

Like radios and select for OR, there should be the AND option for an unspecified list of a thing that is translated to a select[multiple] -- and probably a list of input[type=checkbox] since most users find select[multiple] to be unintuitive to hold ctrl/option (although it's debatably a better UX on mobile to get a native pop-up with checkbboxes).

Question about message types

I'm still trying to learn how this library works, so forgive me if this question doesn't make sense.

I was wondering why the message alias is the same for change messages and messages when the form is valid. I was trying to follow along with this article which creates the form with UserDetails as the output. (However, in the elm docs and examples, I see it's done differently.)

I wanted to be able to put my forms in a separate module and include them where they're needed, but because the msg alias is the same, I can't figure out how to make it work. I need to specify a message as a function that takes a type and returns a msg, but on change, the type will be the values, and on submit it will be the output.

Here's the function signature to be clear what I'm referring to:

asHtml : ViewConfig values msg -> Form values msg -> Model values -> Html msg

type alias ViewConfig values msg =
    { onChange : Model values -> msg
    , action : String
    , loading : String
    , validation : Validation
    }

`succeed` seems like the wrong name.

Why not use the name singleton like many other libraries for succeed : a -> Form b a? ...Like List.singleton, Dict.singleton, Set.singleton, RemoteData.singleton(this one is actually succeed), etc..

Disable a single field

I haven't been able to come up with any solution to disable a single field, based on some truth value.

I have a solution for disabled an entire form, but that can't be used as it needs to be a single field.

defaultConfig : Bool -> CustomConfig msg (Element msg)
defaultConfig readOnly  =
    { form = form readOnly
    , textField = setDisabled readOnly >> textField
    , emailField = setDisabled readOnly >> emailField
    , passwordField = setDisabled readOnly >> passwordField
    , searchField = setDisabled readOnly >> textField
    , textareaField = setDisabled readOnly >> textareaField
    , numberField = setDisabled readOnly >> numberField
    , rangeField = setDisabled readOnly >> rangeField
    , checkboxField = setDisabled readOnly >> checkboxField
    , radioField = setDisabled readOnly >> radioField
    , selectField = setDisabled readOnly >> selectField
    , group = group
    , section = section
    }

setDisabled : Bool -> { a | disabled : Bool } -> { a | disabled : Bool }
setDisabled readOnly config =
    if readOnly then
        { config | disabled = True }

    else
        config

I can't see how I can get access to the config when in building the form though.

I could possibly do something really hacky like feed in a dictionary of field labels and a truth value to my CustomConfig, and then if the labels match (assuming unique), set disabled to true. Or, I could set the error to some specific value, which also is hacky. Or, I could hijack the placeholder field to do a similar thing.

Could this possibly be made a first class thing? It seems like a common behaviour imo

Controlling layout and styling

I like the API and general idea of this a lot but I'm struggling to figure out how to use it with varying layouts and styles of form elements. For instance, in Form.View.basic, each field is rendered with the same styling and there is no control of layout, they're vertically stacked. Even if I wanted to add some content between fields, it's not possible.

Do you have any ideas on how to change the rendering functions to accommodate this?

How to optionally append a form

I'm wondering what the best way would be to add a form using append, iff based on some boolean value?

For my use case, I have a select fields, and based on the value, I'd like to show 2 other fields. I'd do something like:

  |> \form ->
    if truth then
      Form.append someField form
    else
      form

The issue with this is that the output is now different. I'd have to do the same truth test before my call to succeed and feed in the appropriate constructor—or I suppose I could keep the same constructor, but wrap that value in a Maybe.

I looked at the dynamic form example and it uses andThen to do something based on the form, but because of how the form is structured, it doesn't quite work.

Just on a related note, I've got a helper function I use elsewhere for optionally making a field optional:

{-| This will make a field optional dependent upon some test function of the current
form values. The field's parser is only called when the field is considered to be
not blank (for example, an input field isn't empty).
-}
optionalWhen : Form.Form values output -> output -> (values -> Bool) -> Form.Form values output
optionalWhen field default test =
    Form.meta
        (\values ->
            if test values then
                field

            else
                Form.map (Maybe.withDefault default) (Form.optional field)
        )

Form.View.Model not reflecting error state

Hi,

Form.View.Model does not seem to update state + errorTracking upon an invalid form validation.

I've been trying out this library and enjoy using it a lot. However, I'm unsure of the function of the errorTracking that comes with Form.View.Model? This is to propagate what fields in a form are invalid?

I tried out some of the provided examples, filling them out in an invalid way such that multiple field errors were displayed. However, the state of errorTracking becomes

 { errorTracking = 
      ErrorTracking { showAllErrors = True, showFieldError = Set.fromList [] }
 }

I.e. showAllErrors is switched from False => True but showFieldError remains empty, which seems like unexpected behaviour?

Furthermore the state of the Form.View.Model remains Idle rather than Error. I would have expected the state to be Error?

Am I misunderstanding the intended behaviour of these fields or is there a real bug?

Unexpected textarea behavior

I am having trouble with the textareaField and Form.View.idle in the following code. When the form is submitted, the other fields are set to blank, but the textarea doesn't change. See Ellie snippet here: https://ellie-app.com/5sbKCffdg9Ba1

module Main exposing (..)

import Browser exposing (Document)
import Form exposing (Form)
import Form.View
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)

type alias Flags = ()

type Msg
  = FormChanged (Form.View.Model Values)
  | Submit Values

type alias Values =
  { title : String
  , body  : String 
  , pword : String 
  , email : String }

form : Form Values Msg
form =
  let
    titleField =
      Form.textField
        { parser = Ok
        , value = .title
        , update = \value values -> { values | title = value }
        , attributes = { label = "Title", placeholder = "Some title here" } 
        }

    bodyField =
      Form.textareaField
        { parser = Ok
        , value = .body
        , update = \value values -> { values | body = value }
        , attributes = { label = "Body", placeholder = "Your body" } 
        }

    passwordField =
      Form.passwordField
        { parser = Ok
        , value = .pword
        , update = \value values -> { values | pword = value }
        , attributes = { label = "Password", placeholder = "A password" } 
        }

    emailField =
      Form.emailField
        { parser = Ok
        , value = .email
        , update = \value values -> { values | email = value }
        , attributes = { label = "Email", placeholder = "Some email here" } 
        }

    in Form.succeed Values 
        |> Form.append titleField
        |> Form.append bodyField
        |> Form.append passwordField
        |> Form.append emailField
        |> Form.map Submit

type alias Model = { form : Form.View.Model Values }

subscriptions : Model -> Sub Msg
subscriptions _ = Sub.none

init : Flags -> ( Model, Cmd Msg )
init _ = 
  ( { form = { title = "", body = "", pword = "", email = "" } |> Form.View.idle }
  , Cmd.none )

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
  case msg of
    FormChanged modelValues ->
      ( { model | form = modelValues }, Cmd.none )
    Submit output ->
      let initial = { title = "", body = "", pword = "", email = "" }
       in ( { model | form = initial |> Form.View.idle }
          , Cmd.none )

view : Model -> Document Msg
view model = 
  let formView = 
        Form.View.asHtml 
          { onChange   = FormChanged
          , action     = "Submit"
          , loading    = "Submit"
          , validation = Form.View.ValidateOnSubmit
          } form model.form 
   in 
       { title = "", body = [ formView  ] }

main : Program () Model Msg
main =
  Browser.document
    { init          = init
    , update        = update
    , subscriptions = subscriptions
    , view          = view }

Solution to Select for any type, not just Strings

For a long time I thought this was impossible to do without writing toString/fromString functions for your custom types, but I just realized that you can make it work by instead using the list index of the options as the "value", and then in the onChange decoder use that index to retrieve the item from the passed in options list.

Here's a demo: https://ellie-app.com/7253Q8THR2xa1

Rename to `elm-form` (?)

Many well-known packages use the elm- prefix (style-elements is elm-ui now, etc.).

Should we rename this package to elm-form? I think it could help new users to find it.

Form Success State

Hey,
i have a Form with the need to display a Success Message once the submission has succeeded. However i'am stuck because Form.View.State doesn't handle the Success case.

I was thinking about this kind of update on the State type :

type State
    = Idle
    | Loading
    | Error String
    | Success String

Is it a good idea ? or is there an other way to handle that ?

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.