Skip to content
This repository has been archived by the owner on May 2, 2024. It is now read-only.

How to update multiple form elements at once #68

Closed
simonh1000 opened this issue Dec 7, 2016 · 6 comments
Closed

How to update multiple form elements at once #68

simonh1000 opened this issue Dec 7, 2016 · 6 comments

Comments

@simonh1000
Copy link
Contributor

simonh1000 commented Dec 7, 2016

I have a form to select products. After you have selected some parameters, the list of remaining possible options is shown. When you click one all the remaining parameter selects are completed for you.

I used to use Form.Reset to create a message with multiple form values, which I then intercepted in the update function to get the list and add those to the model, rather than letting the list be used to reinitialise the form.

Now the problem for me is that Form.Reset takes List ( String, Field ) whereas the update function needs Fieldvalues, and there is no function Field -> Fieldvalue

So far I've come up with

        FormMsg (Form.Reset lst) ->
            let
                reinitialisedForm =
                    Form.update (Form.Reset lst) model.form

                changedFields =
                    model.form
                        |> getChangedFields
                        |> Set.remove "Finish"
                        |> Set.remove "Height"
                        |> Set.remove "Width"
                        |> Set.remove "Weight"
                        |> Set.insert "Product"
                        |> Set.toList

                go : String -> SpecsEditor.Model -> SpecsEditor.Model
                go fname acc =
                    case getFieldAsString fname model.form |> .value of
                        Just val ->
                            Form.update (Form.Input fname Form.Text <| Field.String val) acc

                        Nothing ->
                            acc

                newForm =
                    L.foldl go reinitialisedForm changedFields
            in
                { model | form = newForm }
@pablohirafuji
Copy link
Contributor

pablohirafuji commented Dec 8, 2016

Let me see if I understood correctly. You want to dinamically change the form field's values based on the value of other fields, while keeping some values?

If that is correct, I would use the Form.inital function to fill the form, because then you could change the fields based on the changed input you would like to listen for changes. Like:

    FormMsg (Form.Input "fieldToListen" inputType fieldValue) ->
      let
         newFormValue : List (String, Field)
         newFormValue =
            [ ( "fieldToListen", Field.value fieldValue )
            , Form.Init.setString "changeThiField" "toThisValue"
            , Form.Init.setBool "changeThiFieldToo" False
            ]

      in
        { model | form = Form.inital newFormValue formValidation }

Note: I haven't used the lastest version of the package, still didn't update my code to Elm 0.18. Code based on the lastest docs (elm-form 1.0.0), didn't test. I don't know if it's the best approach, but it is the one I use (elm-simple-form 4.0.0) and works pretty well.

@simonh1000
Copy link
Contributor Author

simonh1000 commented Dec 9, 2016

The problem with your example above is that you only handle one Form.Input message, which is what the library does anyway. The value of the Reset message is that you can pass a list of (input, value), but the challenge is that you cannot then work with them as easily as before. The code snippet above shows a way of tunneling multiple messages in a Reset but it is not very elegant.

I have another part of my app that has

        FormMulti msgs ->
            let
                newForm =
                    L.foldl Form.update model.form msgs

             
            in
                ( { model | form = newForm }
                , Cmd.none
                )

But this was possible because my Html elements did not have to return Form.Msg.

@etaque
Copy link
Owner

etaque commented Dec 16, 2016

Ok I see the problem. The desired function is Form.Tree.asValue, but isn't exported as the tree structure is an implementation detail:
https://github.com/etaque/elm-form/blob/master/src/Form/Tree.elm#L97

(note that type alias Field = Tree FieldValue)

Would a BatchInput (List (String, InputType, FieldValue)) message solve your case? How and from where would you emit this message?

@simonh1000
Copy link
Contributor Author

I'm not sure whether the Input type is necessary, in that it is implicit in the field name, but otherwise this would be ideal. The key need is to be able to create this BatchInput in the view function. I might have function that wants to return a Html Form.Msg but with multiple form updates. When I have a different return type I can create my own message to carry the data to update and then build Form.Msg from those to fold into the form.

(I have to say I don't really see the the need for the Field and Fieldvalue, as everything seemed to work well before.)

@etaque
Copy link
Owner

etaque commented Dec 21, 2016

(I have to say I don't really see the the need for the Field and Fieldvalue, as everything seemed to work well before.)

That's because the Tree structure has been extracted since list validation, before that logic was duplicated and scattered between field values and errors.

@etaque
Copy link
Owner

etaque commented Mar 22, 2017

doc needs tracked in #85

@etaque etaque closed this as completed Mar 22, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants