6

I'm trying to use a Spring variable in javascript:

Map<String, List<String>> states;

and I found some information here

so I tried:

<script th:inline="javascript">
  /*<![CDATA[*/ 
    var xxx = ${states};
    console.log(xxx);
  /*]]>*/
</script>

In my browser's source tab I have something like:

var xxx = {STATE1=[a, b, c, d]};
console.log(xxx);

and the error is: Uncaught SyntaxError: Invalid shorthand property initializer.

I also tried with: var xxx = /*[[${states}]]*/ 'foo'; and if i print console.log(xxx), I got 'foo'.

NikNik
  • 2,191
  • 2
  • 15
  • 34
  • did you tried wrapping the `xxx` variable value with quotes to make it a string? just to check! – Imesh Chandrasiri Aug 29 '17 at 08:10
  • It is working with `''` but the problem is that in this way I don't have object (hashmap) but String so I can't do something like `xxx['STATE1']` – NikNik Aug 29 '17 at 08:22
  • It looks like your map is serialized in a strange way. According to [doc](http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#advanced-inlined-evaluation-and-javascript-serialization) thymeleaf should write Maps correctly. Do you have the Jackson library in your classpath? – Jakub Ch. Aug 29 '17 at 08:30
  • I do have it. I'm passing the hashmap in this way: `Map> states... model.addAttribute("states", states);` @JakubCh. – NikNik Aug 29 '17 at 08:40
  • @ImeshChandrasiri Sorry, I forgot to tag you in my comment. – NikNik Aug 29 '17 at 08:51
  • @DmitrySenkovich You're right but still I can't parse this object with `JSON.parse/$.parseJSON: {STATE1=[a, b, c, d]}` (this is not valid JSON) – NikNik Aug 29 '17 at 09:03
  • @ImeshChandrasiri I posted my solution. Thank you for help :) – NikNik Aug 29 '17 at 11:54
  • @JakubCh. I posted my solution. Thank you for help :) – NikNik Aug 29 '17 at 11:54

2 Answers2

3

This error is due to {STATE1=[a, b, c, d]} is invalid Javascript object.

The explanation is very trivial: you're seeing the product of server side rendering (you're using Thymeleaf as fat as I can suggest by th:inline tag). So on the server your map object get's rendered as {STATE1=[a, b, c, d]} string. On your client (browser) you get the page with this string, nothing else. There is already no any Java object. Just string. And this string is invalid initialization of an object in Javascript.

So you simply cannot use map this way. You cannot parse this with JSON.parse because it is invalid JSON (there should be : used instead of =).

Hope this helps!

P.S. If you will try to replace = with : in Javascript it will work the other way than you expect: the array [a, b, c, d] will be treated as an array of variables with the names a, b, c and d so you will have to ecnlose it in ''. But I suggest to throw away this idea and rethink you approach. It is not the way it should be used.

Dmitry Senkovich
  • 5,521
  • 8
  • 37
  • 74
  • @NikNik as Java object - for sure. using server side rendering you will get string representation. you can make the dirty hack: make a wrapper object with the map field and override `toString` so that you could generate there valid JSON. it should work, however it is so dirty that I wouldn't touch that with a sixty-foot pole (Cartman from South Park (c)). you should write it in response body (on server) and make an AJAX call in Javascript (if you're not planning to use any frontend frameworks like AngularJS, Angular, ReactJS, VueJS and etc). – Dmitry Senkovich Aug 29 '17 at 09:20
  • I posted how I solved my problem. Thank you for you effort :) I upvoted your answer. – NikNik Aug 29 '17 at 11:52
1

I solved my problem using your comments:

1) There was missing single quote:

<script th:inline="javascript">
  /*<![CDATA[*/ 
    var xxx = '${states}';
    console.log(xxx);
  /*]]>*/
</script>

2) The object must be parsed so:

  var hashmap = $.parseJSON(xxx);

3) And before I need to serialize my object (this is not ajax call so I need to serialize it manually):

Map<String, List<String>> states...
  model.addAttribute("states", new ObjectMapper().writeValueAsString(states));

So now I'm able to read my object:

var myList = hashmap['STATE1'];
console.log(myList ) 

will print [a, b, c, d] and I can loop over:

for(i in myList ){
  console.log(myList[i]);
}
NikNik
  • 2,191
  • 2
  • 15
  • 34