[web-devel] [Haskell-beginners] Options for creating a multiple select form via Yesod
Michael Litchard
michael at schmong.org
Thu Jun 16 01:06:56 CEST 2011
Nope. My mistake, this new code is adding different features.
On Wed, Jun 15, 2011 at 4:02 PM, Michael Litchard <michael at schmong.org> wrote:
> I took a look at
> hello-forms.hs
> and this was my clue
> myForm = fixType $ runFormGet $ renderDivs $ pure (,,,,,,)
> <*> areq boolField "Bool field" Nothing
> <*> aopt boolField "Opt bool field" Nothing
> <*> areq textField "Text field" Nothing
> <*> areq (selectField fruits) "Select field" Nothing
> <*> aopt (selectField fruits) "Opt select field" Nothing
> <*> aopt intField "Opt int field" Nothing
> <*> aopt (radioField fruits) "Opt radio" Nothing
>
>
> The aopt and areq look new. As far as I can tell, this looks like it
> should do what I needed. I'm eager to try it out.
>
>
>
> On Wed, Jun 15, 2011 at 3:59 PM, David McBride <dmcbride at neondsl.com> wrote:
>> I haven't finished. I was making the changes he suggested, but found
>> a problem. I sent him a question but he's probably a busy guy.
>>
>> I don't see the changes in his github page, where are you getting this
>> from? If you have found them, it is just a matter of taking the
>> package, cabal configure, cabal install and then it should be
>> available for all your coding needs.
>>
>> On Wed, Jun 15, 2011 at 6:40 PM, Michael Litchard <michael at schmong.org> wrote:
>>> David,
>>> I checked-out yesod-forms from the repository and see that
>>> you've made the changes. Thank you once again. My follow-up question
>>> is for anyone who cares to answer. How do I swap the new yesod-forms
>>> and the old one from 0.2.0? I don't want to hose
>>> my system. This is new ground for me.
>>>
>>> On Tue, Jun 14, 2011 at 10:56 AM, Michael Litchard <michael at schmong.org> wrote:
>>>> Oh sweet! Thanks!
>>>>
>>>> On Tue, Jun 14, 2011 at 9:43 AM, David McBride <dmcbride at neondsl.com> wrote:
>>>>> I think I'll give it a shot. Fun problem and something I'll
>>>>> definitely need eventually. I'll try and get you a pull request
>>>>> tonight if all goes well.
>>>>>
>>>>> On Tue, Jun 14, 2011 at 11:40 AM, Michael Snoyman <michael at snoyman.com> wrote:
>>>>>> Hi David,
>>>>>>
>>>>>> Thank you for the analysis, you're absolutely correct that this is a
>>>>>> shortcoming in the API of yesod-form as it stands. I had an idea for a
>>>>>> possibly simple modification to fix the situation: change fieldParse
>>>>>> to
>>>>>>
>>>>>> [Text] -> Either msg (Maybe a)
>>>>>>
>>>>>> We don't really want to support returning singles or doubles from the
>>>>>> same Field; a multiSelectField will automatically make the "a"
>>>>>> variable a list. Said another way, the types should be:
>>>>>>
>>>>>> selectField :: [(Text, a)] -> Field xml msg a
>>>>>> multiSelectField :: [(Text, a)] -> Field xml msg [a]
>>>>>>
>>>>>> Another related change: we don't really need to separate out
>>>>>> fieldRender from fieldView I believe. Instead, we can have fieldView
>>>>>> be:
>>>>>>
>>>>>> fieldView :: Text -- ^ ID
>>>>>> -> Text -- ^ name
>>>>>> -> a -- currently, this is another Text
>>>>>> -> Bool -- ^ required?
>>>>>> -> xml
>>>>>>
>>>>>> I'm willing to test out these changes myself, but wanted to (1) get
>>>>>> input from you and (2) see if you or anyone else wanted to take a
>>>>>> crack at it.
>>>>>>
>>>>>> Michael
>>>>>>
>>>>>> On Tue, Jun 14, 2011 at 4:25 PM, David McBride <dmcbride at neondsl.com> wrote:
>>>>>>> I gave a shot at this last night,and didn't quite pull it off. But I
>>>>>>> got pretty far and I'd rather you have my work than try it from
>>>>>>> scratch.
>>>>>>>
>>>>>>> The first method won't work because the Field type is used in
>>>>>>> validating the get parameters in the mhelper function in
>>>>>>> yesod.form.functions. That means that you have to have a unified type
>>>>>>> for field that can do everything. Maybe there is a more succinct way
>>>>>>> with classes, but I just couldn't think of an elegant way to do it
>>>>>>> that way.
>>>>>>>
>>>>>>> So what I tried to do was make the fieldParser callback into its own type:
>>>>>>>
>>>>>>> newtype FieldParser msg a = FieldParser (Either
>>>>>>> (Maybe Text -> Either msg (Maybe a))
>>>>>>> (Maybe [Text] -> Either msg (Maybe [a])))
>>>>>>>
>>>>>>> That means a field parser can either take one text and return one
>>>>>>> item, or it takes a list and returns a list of items.
>>>>>>>
>>>>>>> Then I went through Yesod.Form.Fields and changed about 12 or 15 references of
>>>>>>> { fieldParse = blank $ \s ->
>>>>>>> to
>>>>>>> { fieldParse = FieldParser . Left $ blank $ \s ->
>>>>>>>
>>>>>>> Cool, now when you write your multipleSelectField, you'll set the fieldParser to
>>>>>>> FieldParser . Right $ etc...
>>>>>>>
>>>>>>> The very last thing you have to do to fix this is the mhelper
>>>>>>> function, which is where I lost steam. Right now it looks up the name
>>>>>>> of the field in the get/post params that were passed in, and then
>>>>>>> hands the value to fieldParse. What it needs to do is check to see
>>>>>>> whether Field Parser is left or right, and then pass in the params
>>>>>>> slightly differently depending on which it is. I don't know how the
>>>>>>> parameters will end up getting passed into askParams though. Right
>>>>>>> now askParams returns a list of names to value pairs, so hopefully you
>>>>>>> will end up with a list of multiple entries for the name of your mutli
>>>>>>> select and a different value for each entry, which you need to filter
>>>>>>> out and collect into a single list and then run the fieldParser on it.
>>>>>>>
>>>>>>> Hopefully that is not too bad.
>>>>>>>
>>>>>>>
>>>>>>> On Tue, Jun 14, 2011 at 4:30 AM, Michael Litchard <michael at schmong.org> wrote:
>>>>>>>> Well I will try the easier way first, and having accomplished that I
>>>>>>>> will look into doing it the better way. If people can call dibs, I'd
>>>>>>>> like to.
>>>>>>>>
>>>>>>>> On Mon, Jun 13, 2011 at 9:47 PM, David McBride <dmcbride at neondsl.com> wrote:
>>>>>>>>> After looking at the source, you should be aware that
>>>>>>>>>
>>>>>>>>> 1) yesod-form has been updated to 2.0,
>>>>>>>>> 2) it is a lot easier to understand than 1.x was.
>>>>>>>>>
>>>>>>>>> The main obstacle I see is that the library uses the Field datatype,
>>>>>>>>> that has a fieldParse method of Maybe Text -> Either msg (Maybe a).
>>>>>>>>> The problem with that is that a multiple select box should require
>>>>>>>>> [Text] or perhaps Maybe [Text] rather than Maybe Text. It is making
>>>>>>>>> the assumption that there can only be one piece of data per field,
>>>>>>>>> which holds for everything except multiple selects and multiple radio
>>>>>>>>> buttons.
>>>>>>>>>
>>>>>>>>> So looking at this, it looks like you'd have to add another field type
>>>>>>>>> "FieldMulti" to Yesod/Form/Types.hs, which allows for multiple values.
>>>>>>>>> Then add a new version of selectFieldHelper that accepts fieldMultis
>>>>>>>>> instead of fields, and then it is trivial to change selectField to be
>>>>>>>>> a multi field.
>>>>>>>>>
>>>>>>>>> Alternatively you could change Field to accept either single or
>>>>>>>>> multiple values and change its use everywhere else, which is probably
>>>>>>>>> the better answer, but more involved.
>>>>>>>>>
>>>>>>>>> I don't know if this is the best way to go about it, but it seems like
>>>>>>>>> it should work.
>>>>>>>>>
>>>>>>>>> On Mon, Jun 13, 2011 at 8:11 PM, Michael Litchard <michael at schmong.org> wrote:
>>>>>>>>>> Thank you David. I'm trying to figure out step-by-step, exactly how
>>>>>>>>>> selectFields binds field values. One thing I'm having trouble with is
>>>>>>>>>> visualizing return values.
>>>>>>>>>> Beginning with askParams.
>>>>>>>>>>
>>>>>>>>>> askParams :: Monad m => StateT Ints (ReaderT Env m) Env
>>>>>>>>>> askParams = lift askenv <- askParams
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Here's the example from selectFields
>>>>>>>>>> env <- askParams
>>>>>>>>>> later on env is used in with the lookup function
>>>>>>>>>>
>>>>>>>>>> let res = case lookup name env of
>>>>>>>>>> seeing as lookup is checking for value of type a in a [(a,b)]
>>>>>>>>>> and given the type of askParams
>>>>>>>>>> I have no idea what is going on here. I don't see a [(a,b)] in
>>>>>>>>>> askParams :: Monad m => StateT Ints (ReaderT Env m) Env.
>>>>>>>>>>
>>>>>>>>>> So if someone could answer how env <- askParams yields a [(a,b)] for
>>>>>>>>>> lookup to use as input, I would appreciate it.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Mon, Jun 13, 2011 at 2:54 PM, David McBride <dmcbride at neondsl.com> wrote:
>>>>>>>>>>> The read function is sort of the opposite of the show function. Take
>>>>>>>>>>> a string, give me a value. reads is like read, however it has some
>>>>>>>>>>> traits that read doesn't have.
>>>>>>>>>>>
>>>>>>>>>>> The problem with read is that if you go: read "asdf" :: Int, it will
>>>>>>>>>>> die with an exception, and that is something you don't want in a web
>>>>>>>>>>> app. Also it doesn't tell you what the rest of the string is, so you
>>>>>>>>>>> have no real way of finding out what was left of the string after the
>>>>>>>>>>> part you wanted to parse.
>>>>>>>>>>>
>>>>>>>>>>> So there is the reads function that returns [(a,String)] which is a
>>>>>>>>>>> list of pairs of the answer a, and the rest of the string String. As
>>>>>>>>>>> a bonus, it returns a list so if it can't parse the string you pass
>>>>>>>>>>> it, then it just returns an empty list. Why didn't it use Maybe you
>>>>>>>>>>> ask? I bet it probably has to do with the function being one of the
>>>>>>>>>>> first functions ever written for haskell, long before Maybe existed.
>>>>>>>>>>>
>>>>>>>>>>> So all it is there is unpack this bytestring into a string, then parse
>>>>>>>>>>> it into a value, and please don't blow up if the input is invalid.
>>>>>>>>>>>
>>>>>>>>>>> On Mon, Jun 13, 2011 at 5:28 PM, Michael Litchard <michael at schmong.org> wrote:
>>>>>>>>>>>> I was a bit hasty. I can render a multi-select field easily enough.
>>>>>>>>>>>> However, I'm having difficulty following how selectField makes a value
>>>>>>>>>>>> from the select field accessible from the handler code calling
>>>>>>>>>>>> selectField. Once I figure that out, I can modify multiSelectField
>>>>>>>>>>>> accordingly.
>>>>>>>>>>>>
>>>>>>>>>>>> The goal here being to modify selectField so that a list of field
>>>>>>>>>>>> values can be bound .
>>>>>>>>>>>>
>>>>>>>>>>>> Here's what I have so far:
>>>>>>>>>>>> multiSelectField is thus far identical in every way to selectField
>>>>>>>>>>>> save for the following change in the Hamlet part.
>>>>>>>>>>>>
>>>>>>>>>>>> <select multiple="#{theId}" id="#{theId}" name="#{name}">
>>>>>>>>>>>>
>>>>>>>>>>>> My thinking was that the value bound to multiple was arbitary, and I'd
>>>>>>>>>>>> use theId until I figured out something that made more sense.
>>>>>>>>>>>>
>>>>>>>>>>>> Here's where I am focusing my efforts next
>>>>>>>>>>>>
>>>>>>>>>>>> http://hpaste.org/47774
>>>>>>>>>>>>
>>>>>>>>>>>> Specifically
>>>>>>>>>>>> (x', _):_ ->
>>>>>>>>>>>> case lookup x' pairs' of
>>>>>>>>>>>> Nothing -> FormFailure ["Invalid entry"]
>>>>>>>>>>>> Just (y, _) -> FormSuccess y
>>>>>>>>>>>> I'm thinking this is where selectField binds a value from the select
>>>>>>>>>>>> field form. I'm confused by the (x',_):_. At first I thought it meant
>>>>>>>>>>>> that just the first pair in a list of pairs is pattern matched
>>>>>>>>>>>> against, and the rest discarded. But then I ask myself where the list
>>>>>>>>>>>> is coming from. In a select field there would only be one pair, not a
>>>>>>>>>>>> list of them. Here's where I get confused. Because if this is not
>>>>>>>>>>>> where the values of the select field get bound, I don't know where
>>>>>>>>>>>> it's happening.
>>>>>>>>>>>>
>>>>>>>>>>>> Is my confusion clear enough such that I could get some clarifying
>>>>>>>>>>>> feedback? If not, what is unclear?
>>>>>>>>>>>>
>>>>>>>>>>>> On Sat, Jun 11, 2011 at 11:03 AM, Michael Snoyman <michael at snoyman.com> wrote:
>>>>>>>>>>>>> The best way for code contributions in general is to submit a pull
>>>>>>>>>>>>> request on Github. If that's a problem, sending a patch via email
>>>>>>>>>>>>> works as well (either directly to me or to web-devel).
>>>>>>>>>>>>>
>>>>>>>>>>>>> Michael
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Sat, Jun 11, 2011 at 1:14 AM, Michael Litchard <michael at schmong.org> wrote:
>>>>>>>>>>>>>> Hey! I just added multiSelectField to the Forms library. I'm only
>>>>>>>>>>>>>> getting the first value selected, but I think that's because of how
>>>>>>>>>>>>>> I'm using multiSelecrField. I'm going to try to change the client code
>>>>>>>>>>>>>> to fix this. I'll let you know how it goes. when I get a
>>>>>>>>>>>>>> maybeMultiSelectField added I'll show you what I have. What would be
>>>>>>>>>>>>>> the best way to submit this?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Thu, Jun 9, 2011 at 10:05 PM, Michael Snoyman <michael at snoyman.com> wrote:
>>>>>>>>>>>>>>> Hi Michael,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> There's nothing jQuery or Javascript specific about a multi-select
>>>>>>>>>>>>>>> field: it's just a normal select field with a "multiple" attribute. I
>>>>>>>>>>>>>>> would recommend taking the selectField code from yesod-form and
>>>>>>>>>>>>>>> modifying it to be multi-select. I'll likely do this myself
>>>>>>>>>>>>>>> eventually, but it could be a good learning experience in Yesod (and a
>>>>>>>>>>>>>>> great introduction to contributing to the framework if you're so
>>>>>>>>>>>>>>> inclined).
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Michael
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Thu, Jun 9, 2011 at 8:29 PM, Michael Litchard <michael at schmong.org> wrote:
>>>>>>>>>>>>>>>> I'm trying to create a multiple select form, as illustrated on the following:
>>>>>>>>>>>>>>>> http://api.jquery.com/selected-selector/
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Here's the options I see possible:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> (1) Write a jQuery widget.
>>>>>>>>>>>>>>>> (2) Use plain javascript via Julius
>>>>>>>>>>>>>>>> (3) Use the low-level functions in Yesod.Form to write a widget
>>>>>>>>>>>>>>>> (4) Use a pre-existing function that does what I need, but am not
>>>>>>>>>>>>>>>> aware of this functionality
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> (1) has appeal as it looks like something small I can contribute to
>>>>>>>>>>>>>>>> the project. It will take me some extra time to figure out the
>>>>>>>>>>>>>>>> details. But, I had a look at the other jQuery widgets and they seem
>>>>>>>>>>>>>>>> to provide an approachable model to follow.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> (2) This looks like the most straight-forward approach. I'm just
>>>>>>>>>>>>>>>> learning javascript so would have to figure out how to capture values
>>>>>>>>>>>>>>>> in Haskell from the form.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> (3) This looks like the most difficult way. I don't think I know
>>>>>>>>>>>>>>>> enough about the low-level functions in Yesod.Form to be able to
>>>>>>>>>>>>>>>> accomplish this in a timely manner.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> (4) This is the best scenario. There's already a way to do this right
>>>>>>>>>>>>>>>> now, and I just haven't identified it. If this is the case, I would
>>>>>>>>>>>>>>>> appreciate being pointed in the right direction.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Until informed otherwise, I'm evaluating options 1 and 2. All feedback
>>>>>>>>>>>>>>>> welcomed. Thanks to all who made Yesod possible.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>>>>>> Beginners mailing list
>>>>>>>>>>>>>>>> Beginners at haskell.org
>>>>>>>>>>>>>>>> http://www.haskell.org/mailman/listinfo/beginners
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>> Beginners mailing list
>>>>>>>>>>>> Beginners at haskell.org
>>>>>>>>>>>> http://www.haskell.org/mailman/listinfo/beginners
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> _______________________________________________
>>>>>>>>>>> Beginners mailing list
>>>>>>>>>>> Beginners at haskell.org
>>>>>>>>>>> http://www.haskell.org/mailman/listinfo/beginners
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> Beginners mailing list
>>>>>>>>> Beginners at haskell.org
>>>>>>>>> http://www.haskell.org/mailman/listinfo/beginners
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> Beginners mailing list
>>>>>>> Beginners at haskell.org
>>>>>>> http://www.haskell.org/mailman/listinfo/beginners
>>>>>>>
>>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> Beginners mailing list
>>>>> Beginners at haskell.org
>>>>> http://www.haskell.org/mailman/listinfo/beginners
>>>>>
>>>>
>>>
>>
>
More information about the web-devel
mailing list