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

Unable to set String as innerHTML #408

Closed darthdeus closed 9 years ago

darthdeus commented 10 years ago

I've been trying to create a simple app based on the Yesod Fay scaffolding, but I'm having trouble with setting a String I got back via an AJAX command as a <textarea>'s innerHTML.

Here's the exact code. I haven't really modified anything from the scaffodling, just added a new sum type for my command, returning a simple String from the backend, and trying to set that String in an element.

What I've found is that if I do this setInnerHTML jsout text, the <textarea> remains blank. But if I do setInnerHTML jsout $ show text, it will set the content (even though it adds the double quotes around the String. Setting a specific literal works as well, for example setInnerHTML jsout "foobar", so the problem is probably in the way it gets deserialized from the AJAX call.

I've checked the AJAX response and the text is there, so I'm not really sure what could be causing this, or even how to debug this.

What I've found is that if I add a print statement, such as

Just text -> do
  print text
  setInnerHTML jsout text

the text gets logged in correctly, but doing so with putStrLn it will just log a blank line, like this

Just text -> do
  putStrLn text
  setInnerHTML jsout text
darthdeus commented 10 years ago

I also tried checking the value before setting it using the JS debugger as described here #389, but it turns out that the value for text ends up being "", while for show text it's the correct string wrapped in double quotes. Why is this happening?

bergmark commented 10 years ago

Using Strings together with polymorphism in the FFI causes problems, you should use the fay-text Text type instead, it's more efficient and doesn't cause problems.

darthdeus commented 10 years ago

I'm a bit confused, since setInnerHTML isn't polymorphic in this case, and it actually comes from the sample code from yesod-fay, and all of the examples in fay itself show Strings. Or is this being caused by print/show on the String?

Is the rule of thumb to always, everywhere use Text? Or in which cases is it to use String with fay?

bergmark commented 10 years ago

The Fay examples use String to not incur the the dependency (something that should probably be clarified more), I recommend using Text for everything.

i'm not that familiar with yesod fay, but call does an ajax call right? That means that the returned value has to go through an Automatic deserialization which causes problems with String. Also note that show and print have the argument type Automatic a so in that case you are going from one Automatic conversion to another, and i'm not sure what happens then :-) If you want to print the exact value of something without doing any conversions you can use

printPtr :: Ptr a -> Fay ()
printPtr = ffi "(function(x) { if (console && console.log) console.log(x) })(%1)"
darthdeus commented 10 years ago

Yes call in this example does AJAX. Sorry for asking so many questions, but what kind of problems? I've been looking at the source for fay and fay-base but couldn't really find anything.

bergmark commented 10 years ago

No worries!

Fay Strings are represented as [Char] as in Haskell. If you have a conversion fay -> json and the type in the FFI is String it will convert String -> JS String, but if the type is Automatic a fay won't know to do this and will serialize to an array of one character js strings instead. Conversely when going json -> fay we can't tell that a js string should end up as [Char] and not be kept as is.

fay-text is a more recent addition that came after we discovered this was an issue. We could fix this by always having the array-of-strings representation for String but that would silently break any code that uses String. Hard to tell how many would be affected by this.