Custom attributes in yesod form fields

320 views
Skip to first unread message

mifrai

unread,
Mar 21, 2012, 6:00:16 AM3/21/12
to Yesod Web Framework
I was wondering if it was possible to add custom attributes to input
fields. I specifically want to add data-attributes and the placeholder
attribute.

Unfortunately, it looks like FieldSettings doesn't provide the option
and FieldView doesn't provide something like fvName - so I can't roll
my own while generating it in a custom MForm.

Do you have a suggestion or do I have to write a set of nearly-
duplicate Fields to support this?

Thanks,
- Mike

Lambda

unread,
Mar 22, 2012, 2:48:24 PM3/22/12
to yeso...@googlegroups.com
Hi,

It's not really an answer, but this is what I do:

I don't use the MForm for the markup, only for the logic. Mostly because the MForm-markup is not very versatile, it only allows for a table of div block. You could, instead of using the table markup, just write it yourself as a hamlet widget, making sure the input-names do match. This also works for forms that are submitted via AJAX.

My problem up to now was the Nonce-Value, have not yet found out how to pull it out of the MForm.

Hope that helped.

Michael Snoyman

unread,
Mar 23, 2012, 7:32:45 AM3/23/12
to yeso...@googlegroups.com

Maybe instead of adding classes to FieldSettings, we should have just added arbitrary attributes, which would solve this and a number of other problems. The downside is that, with current Hamlet syntax, it would be very difficult to add arbitrary attributes. Maybe we should also add a new construct (syntax up for debate):

let attrs = [("foo", "bar"), ("baz", "bin")]
     html = [shamlet|<tag @attrs>|]
print html -- <tag foo="bar" baz="bin"></tag>

Any thoughts?

Michael

Greg Weber

unread,
Mar 23, 2012, 8:06:16 AM3/23/12
to yeso...@googlegroups.com
can we just use <tag #{attrs}> ?
That seems like a good default for an alist, but we could instead
require an Attrs constructor.

Felipe Almeida Lessa

unread,
Mar 23, 2012, 8:08:20 AM3/23/12
to yeso...@googlegroups.com
On Fri, Mar 23, 2012 at 8:32 AM, Michael Snoyman <mic...@snoyman.com> wrote:
> Maybe instead of adding classes to FieldSettings, we should have just added
> arbitrary attributes, which would solve this and a number of other problems.
> The downside is that, with current Hamlet syntax, it would be very difficult
> to add arbitrary attributes. Maybe we should also add a new construct
> (syntax up for debate):
>
> let attrs = [("foo", "bar"), ("baz", "bin")]
>      html = [shamlet|<tag @attrs>|]
> print html -- <tag foo="bar" baz="bin"></tag>
>
> Any thoughts?

I like both ideas, but I'd like to bikeshed on the syntax. I think
that @ is bad choice since we may already have something like <a
href=@{RouteR}>. Greg's idea of using # is something I don't like as
well for the same reason. I propose using ^, such as <tag ^{attrs}>.
It's unambigous since ^ can't appear inside tags right now, and
semantically it is close to including a Widget, but on a smaller
scale.

Cheers! =)

--
Felipe.

Michael Snoyman

unread,
Mar 23, 2012, 8:09:33 AM3/23/12
to yeso...@googlegroups.com
I'd be worried about a possible ambiguity in the future. Currently, we
don't allow variable interpolation in attribute keys. In other words,
the following is invalid:

<tag #{key}=value>

But in theory, we might want to add it. Now imagine that key ==
"checked". It would be perfectly reasonable for somebody to want to
write:

<input type=checkbox #{key}>

and expected the result to be "<input type='checkbox' checked>".

The reason I used @ is that XPath uses @ for attributes, but I don't
think it's really good since we use @ for URLs.

Michael

Greg Weber

unread,
Mar 23, 2012, 8:25:05 AM3/23/12
to yeso...@googlegroups.com
I was trying to point out that no special syntax is necessary - we can
just use ToHtml instances.

attr (k,v) = T.concat [k,"=",v])

instance ToHtml [(Text, Text)] where
toHtml = toHtml . T.intercalate " " . map attr

or

instance ToHtml Attrs where
toHtml (Attrs pairs) = toHtml . T.intercalate " " $ map attr pairs

Michael Snoyman

unread,
Mar 23, 2012, 8:26:57 AM3/23/12
to yeso...@googlegroups.com
It wouldn't work: the stuff inside a tag has strict syntax. It must
currently be an #id, .class, attr=val, or :cond:attr=val.

Felipe Almeida Lessa

unread,
Mar 23, 2012, 8:28:47 AM3/23/12
to yeso...@googlegroups.com
On Fri, Mar 23, 2012 at 9:25 AM, Greg Weber <gr...@gregweber.info> wrote:
> I was trying to point out that no special syntax is necessary - we can
> just use ToHtml instances.
>
>    attr (k,v) = T.concat [k,"=",v])
>
>    instance ToHtml [(Text, Text)] where
>      toHtml = toHtml . T.intercalate " " . map attr
>
> or
>
>    instance ToHtml Attrs where
>      toHtml (Attrs pairs) = toHtml . T.intercalate " " $ map attr pairs

I'm not too familiar with ToHtml, but with this works, then I don't
have any problems with it =).

Cheers,

--
Felipe.

Greg Weber

unread,
Mar 23, 2012, 8:41:59 AM3/23/12
to yeso...@googlegroups.com
ok, so it doesn't work right now because we don't allow it.
If we allowed it, someone could easily create invalid Html.
Is there any other downside?

If we want correctness, it may still make sense to re-use #{} but
expand it as toAttribute. I would much prefer that over using @ or ^,
although using an entirely different symbol could be better.

Michael Snoyman

unread,
Mar 23, 2012, 11:14:35 AM3/23/12
to yeso...@googlegroups.com
I personally like the ^{} proposal. It's taking something that
currently makes no sense inside a tag (interpolating an entire
template), and gives it a logical meaning (interpolate a *bunch* of
attributes). I'd like to go that route.

Greg Weber

unread,
Mar 23, 2012, 11:48:22 AM3/23/12
to yeso...@googlegroups.com
I think we need to be very careful about creating context-sensitive
meanings. We will end up with a lot more explaining to do. Although we
don't currently allow ^{} in a tag, I don't see why widget
interpolation never makes sense in a tag. I would be all for ^{} in
the attributes if the attributes were first converted to a widget.

I looked at the source, and realized that for Hamlet we do not have a
ToHtml typeclass right now. I think creating a ToHtml typeclass would
have its own merits - it would give hamlet some of the same
extensibility as the rest of shakespeare.

Another possibility would be to use ^{} as suggested, but with a
ToWidget typeclass that will automatically convert our attributes.

I want to be convinced that we have exhausted the possibilities of our
existing syntax before making it context-sensitive.

Michael Snoyman

unread,
Mar 23, 2012, 11:52:30 AM3/23/12
to yeso...@googlegroups.com
Have to be brief: we do have ToHtml, it's defined in blaze-html. All
the approaches so far are context sensitive. That's why I originally
used a different syntax (@attrs) instead of the existing interpolation
syntaxes.

Greg Weber

unread,
Mar 23, 2012, 11:56:48 AM3/23/12
to yeso...@googlegroups.com
how would a ToHtml instance be context sensitive ?

mifrai

unread,
Mar 24, 2012, 12:52:55 AM3/24/12
to yeso...@googlegroups.com
I'm not sure it's any better than the other ideas, but what about using [attrs] or introducing a new interpolation symbol *{attrs}? 

Here are my thoughts on the various options so far:

<tag @attrs>
+ Familiarity with x-path selectors and existing #id syntax
- Interpolates a value but does not have {}, making it different from #id syntax and possibly confusing
- Does not allow function application
+ Doesn't overload an existing operator

<tag [attrs]>
+ Familiarity with x-path jquery selectors
- Interpolates a value but doesn't follow the _{} interpolation syntax, so it can be construed as entirely new operator class
+ Allows function application, eg <tag [elemAttrs elem]>
+ Doesn't overload an existing operator

<tag ^{attrs}>
- Context sensitive overloading (the type signature is different in different contexts)
+ Semantic sense, but it's stretching it a little (splicing some sort value in)

<tag *{attrs}>
+ Familiar interpolation syntax
+ Doesn't overload an existing operator
- Introduces a new interpolation operator 
Note: I picked *{} because it gives a rough indication that it has to do interpolating zero or more of something.

Michael Snoyman

unread,
Mar 24, 2012, 1:43:36 PM3/24/12
to yeso...@googlegroups.com
That's a really good breakdown, and I think the *{...} might be the
best option so far.

Max Cantor

unread,
Mar 24, 2012, 6:27:54 PM3/24/12
to yeso...@googlegroups.com
This will only augment, not supplant the current HTML-style syntax right? If its a replacement, I'm strongly opposed. Even as an addition, i'm a bit uneasy. Anything that departs from HTMLish syntax adds significantly to the learning curve so we should be careful when doing that.

Greg Weber

unread,
Mar 24, 2012, 9:52:00 PM3/24/12
to yeso...@googlegroups.com
yes, foo=bar is still preferred in your HTML. We are concerned for
what to if you have already built your attributes elsewhere.

I like *{} the best also. I think it is important to stick with our
bracketed interpolation for consistency. I think it is easy to explain
#{} as ToHtml in Hamlet, ToJavascript is Julius, etc, and ^{} as
widget interpolation in all three. Explaining *{} as attribute
interpolation (we will probably end up with a ToAttribute typeclass)
is easy, and we can allow #{} and ^{} in the attributes in the future
if needed.

Michael Snoyman

unread,
Mar 25, 2012, 1:47:31 AM3/25/12
to yeso...@googlegroups.com

Felipe Almeida Lessa

unread,
Mar 25, 2012, 10:52:54 AM3/25/12
to yeso...@googlegroups.com
Great! =)

What about OP's problem with yesod-form, then?

--
Felipe.

Michael Snoyman

unread,
Mar 25, 2012, 11:58:09 AM3/25/12
to yeso...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages