Handling a collection of data in a Yesod Form

独自空忆成欢 提交于 2021-01-27 20:23:53

问题


Is it possible in Yesod to handle forms that contain a collection of data?

I have a form that the user can add multiple people to, on the frontend it currently looks like this:

{ people.map((person, key) => (
  <td>
    <input type="hidden" name={ `person[${key}][firstName]` } value={person.firstName} />
    <input type="hidden" name={ `person[${key}][lastName]` } value={person.lastName} />
    { person.firstName } { person.lastName }
  </td>
)) }

I then want to be able to translate that over to the backend like so:

[Person "Michael" "Snoyman", Person "Ed" "Kmett"]

This list is variable in length, so it could have as many people in the people value as the user likes. So far I've been unable to work out how to replicate this kind of thing using FormInput in Yesod.


回答1:


You could create your own FormInput by defining the unFormInput function. This function could pull the field names from the form, extract the keys, and then you could use ireq to promote the relevant fields.

This could look something like

getPeople :: FormInput (your handler type) [People]
getPeople = FormInput $ \m l env fenv ->
    (unFormInput (peopleField peopleKeys)) m l env fenv
        where
            peopleKeys = getPeopleKeys env

getPeopleKeys

This helper function would produce all the key values for the people in your form. They wouldn't need to be valid yet, since field parsing will take care of that later.

getPeopleKeys :: Env -> [Text]
getPeopleKeys env = mapMaybe extractKey (keys env)
    where
        extractKey :: Text -> Maybe Text
        extractKey key = ... -- you could use e.g. regex here
                             -- to pull the keys out of the field names
                             -- and return Nothing otherwise

peopleField

This helper produces the FormInput. It

  1. takes a list of keys,
  2. generates a FormInput from each one
    1. generates a field for the first name and last name
    2. turns those fields into FormInputs
    3. produces a FormInput which combines them into a Person
  3. concatenates the FormInputs' results into a FormInput ... [Person]

peopleField :: Monad m => RenderMessage (HandlerSite m) FormMessage => [Text] -> FormInput m [Person]
peopleField = mapM personField
    where
        personField :: Text -> Field ... Person
        personField key = (liftA2 (Person)) (personFNameField) (personLNameField)
            where
                personFNameField = (ireq hiddenField) . fNameField key
                personLNameField = (ireq hiddenField) . lNameField key

fNameField key = ... -- this outputs "person[${key}][firstName]"
lNameField key = ... -- etc.


来源:https://stackoverflow.com/questions/52182020/handling-a-collection-of-data-in-a-yesod-form

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!