#2581 Passing complex data through a script block

jhughes Fri 9 Dec 2016

I have a WebMod that gets called and then builds some HTML out for the response on onGet. I have a out.script block in there that calls another fantom method that needs access to the headers from the original request. I cannot seem to find a way to pass this type of variable from the out.script method. Passing a Map isn't supported since it's not valid js syntax. If I quote the map it works but I can't find a way to convert a string back to a map. I was hoping the Map.toCode method would work but that also doesn't seems to be a different string encoding with no way to construct the originating map later.

So I guess the question boils down to, what's the proper way to pass Map, List (non string) data from a WebReq into a fantom method using the script block? Or if it's all string passing, how do I reconstruct these complex data types back from strings?

SlimerDude Fri 9 Dec 2016

Hi Jonathan,

That description is a little difficult to follow, so let me try to re-state the problem...

...you're writing some HTML that contains javascript, and in that javascript you're calling out to a Fantom (javascript) method that takes a Map. Your question is then, how do I serialise a Map to javascript code, so it may be re-constructed and passed to the Fantom method?

In Fantom, to serialise and de-serialise a Map you can use this code:

map    := Str:Str["key-1":"val-1", "key-2":"val-2"]
mapStr := map.toCode

...

newMap := ([Str:Str]) mapStr.in.readObj

To create Javascript code, you can write the Map out like this:

map    := Str:Str["key-1":"val-1", "key-2":"val-2"]
mapStr := map.toCode.toCode('"')
jsStr  := "var mapStr = " + mapStr.toCode('"') + ";"

Then to reconstitute it back to a map:

...
jsStr  += "var newMap = fan.sys.Str.$in(mapStr).readObj();"

The newMap variable can then be passed to a Fantom method.

andy Fri 9 Dec 2016

The "standard" way to pass data from a Weblet to a browser is to use jsMain:

out.docType
out.html
out.head
  out.title.w("Foo").titleEnd
  out.includeCss(...)
  out.includeJs(...)

  env := Str:Str[:]
  env["foo"] = "..."
  env["bar"] = "..."
  ...

  WebUtil.jsMain(out, "myPod::Main", env)
  out.headEnd

out.body.bodyEnd
out.htmlEnd

This will encode your data properly in the request - and then decode as read-only values in Env.vars - which from there you can decode as needed.

Check out the code if you want to see how it works

jhughes Fri 9 Dec 2016

SlimerDude

Those examples helped a lot, I was able to use them to do what I was trying. Good info about the serialization as well, didn't know it was that easy.

Andy I actually found some other code where I had used that technique and updated my code to use it. The other method does allow me to write a script block to pass data directly to the fantom method without having to decode env variables in the method itself. Not sure if i'll actually want to do that but it's good to know that I could.

SlimerDude Sat 10 Dec 2016

Glad it helped.

An extra note on serialization - any Fantom class may be serialized to a human readable string with the following:

str := Buf().writeObj(myObj).flip.readAllStr

The Map.toCode() method is just a convenience for the above.

There's also a chatper called Serialization in the Fantom docs, but that's mainly about how to customise the generated serialization string.

Login or Signup to reply.