faylang / fay

A proper subset of Haskell that compiles to JavaScript
https://github.com/faylang/fay/wiki
BSD 3-Clause "New" or "Revised" License
1.29k stars 86 forks source link

Use FFI for JQuery Validation plugin #427

Closed denisshevchenko closed 9 years ago

denisshevchenko commented 9 years ago

Hello!

I try to use Fay with JQuery Validation plugin in my Yesod-project. So I write:

validateForm :: JQuery -> Fay ()
validateForm = do
    ffi "%1.validate({rules:{newUserEmail:{required:true,email:true}},messages:{newUserEmail:{required: \"Insert your email, please\",email: \"Invalid email\"}}})"

...

main :: Fay ()
main = ready $ do
    select "#registerNewUserForm" >>= validateForm
    return ()

And it works fine. But I cannot add parameter for FFI-string. For example, I try this:

validateForm :: Text -> JQuery -> Fay ()
validateForm = do
    ffi "%2.validate({rules:{%1:{required:true,email:true}},messages:{%1:{required: \"Insert your email, please\",email: \"Invalid email\"}}})"

...

main :: Fay ()
main = ready $ do
    select "#registerNewUserForm" >>= validateForm "newUserEmail"
    return ()

In this case I got error:

fay: templates/home/register/form/Form.hs: (11,1)-(11,13):
invalid JavaScript code in FFI format string:
"validateForm" (line 1, column 139):
unexpected "("
expecting letter or digit or ":"
in ...

How can I fix it?

bergmark commented 9 years ago

We parse FFI expressions using language-ecmascript meaning they need to be a valid javascript expression before the interpolation to replace the % arguments occur.

Keys in JS objects need to be valid identifiers or numbers, to add a dynamic property to them you must assign it with o[key] = value.

A side note: I had to think for a moment to figure out why the first example works! FFI declarations need the type signature immediately surrounding it, f :: X; f = ffi "..." (without do) in a top-level declaration or ffi "..." :: x if it's an internal expression. It seems like the compiler's desugaring phase is accidentally ordered so the redundant do in your first example is removed before ffi desugaring occurs!

Editedit: Oh boy I'm confusing myself thoroughly, but I updated my reply again so now it should be good :-)

denisshevchenko commented 9 years ago

Do you mean I must write like this?

validateForm :: Text -> JQuery -> Fay ()
validateForm = do
    ffi "(function() { var o = {}; o['field'] = %1; %2.validate({rules:{o['field']:{required:true,email:true}},messages:{o['field']:{required: \"Insert your email, please\",email: \"Invalid email\"}}}) })"

But it doesn't work.

bergmark commented 9 years ago

That is also not valid javascript, keys in object literals cannot be dynamic. You probably want something like this:

"var myRules = {}; \
myRules[%1] = {required:true,email:true}; \
[...]
%2.validate({rules: myRules, [...]})"
denisshevchenko commented 9 years ago

Thank you very much! It works now.

bergmark commented 9 years ago

Glad to hear it, you're welcome!