Grails hashmap variable in javascript gives different format - javascript

In my grails controller:
assert result == [hus:['hus#gmail.com', 'SE', 'on', '9908899876'], vin:['vin#gmail.com', 'SD', 'on', '7765666543']]
println "result is::"+result
println result.getClass()
[result:result] //passing model to view
which prints :
[hus:[hus#gmail.com, SE, on, 9908899876], vin:[vin#gmail.com, SD, on, 7765666543]]
class java.util.LinkedHashMap
but when i get this hashmap from my view page and access from javascript
$(function(){
alert('${result}');
});
it prints
{
hus=[hus#gmail.com,SE,9902766542],
vin = [vin#gmail.com, SE,887654433]
}
which is not valid object , is not a valid object, (: replaced by =) it should be
{ hus:[hus#gmail.com,SE,9902766542], vin : [vin#gmail.com, SE,887654433] }
why it is so? how do i correct it?

Your current output is produced by toString() of the Map result which can be used to
print the data but is not very useful to transfer it to javascript.
You should convert the result to json in your controller:
def json = result as JSON
and return it to your model:
[json : json ]
After that you can create an object in Javascript using JQery.parseJSON:
var obj = jQuery.parseJSON("${ json.toString() }");

Related

iOS Swift How to pass JSON String and Array or Dictionary to Javascript from UIWebView?

In my project I have pass String to JavaScript using stringByEvaluatingJavaScript it have passed successfully. But if I have pass JSON String and Array or Dictionary means it doesn't pass the values I don't know how to pass these.
Here I have mention the code I have tried for pass the string to JavaScript,
let param:String = "HI"
let _ = self.webView.stringByEvaluatingJavaScript(from: "myNewFunction('\(param)')")
It Successfully return the value HI
Here I Mentioned the JavaScript Code,
<!DOCTYPE html>
<html>
<p>Click the button to display an alert box.</p>
<script>
function myNewFunction(param) {
alert(param);
}
</script>
<body>
<button onclick="myNewFunction()">Try it</button>
</body>
</html>
How can I pass the values like Array and Dictionary and the JSON String?
let dict:[String:Any] = ["key1":10,"key2":false, "key3": "Some string goes in here"]
let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: [.prettyPrinted])
if let data = jsonData{
let value = String(data: data, encoding: .utf8)
print( value )
}
Output:
Optional("{\n \"key1\" : 10,\n \"key2\" : false,\n \"key3\" : \"Some string goes in here\"\n}")
Code in Playground
Result in Playground
Here what was missing was the dictionary type inference i.e dict:[String:Any]. Also when you use try use optional along with it as it may throw an exception like try?
This might work.. I haven't tested it yet:
if let data = try? JSONSerialization.data(withJSONObject: arrayOrDictionaryHere, options: [.prettyPrinted]), let param = String(data: data, encoding: .utf8) {
self.webView.stringByEvaluatingJavaScript(from: "myNewFunction('\(param)')")
}
//JS:
function myNewFunction(param) {
alert(JSON.parse(param))
}
Use following code for converting dictionary to jsonstring:
var dict : Dictionary = ["key1":"value1","key2":"value2"]
let data = try JSONSerialization.data(withJSONObject: dict, options: [.prettyPrinted])
let value = String(data: data, encoding: .utf8)
and then call your javascript method using the string in value
if you replace dict in second line with and instance of json array then you will get json string of the json array too. I every thing will work for that too.

How to get int array with javascript in play framework template?

When I tried to pass a list to the template I got an error.
The list is defined like:
myList: List<Map<String,int[]>>
Now the data of myList is :
[{First Try=[1,0,0,1], Second Try=[1,1,2,2]}, {}]
I use chart.js to show a chart and so I need a int[] as data list.
my view:
#(myList: List[Map[String,Array[Int]]])
var list = #myList;
for(var i=0;i<list.length;i++){
var map = list[i];
for(var key in map){
myFunction(key,map[key]);
}
}
myFunction(string,array){
//I want directly use the array to the chart’s datasets
//others
var myChart = new Chart(chartid, {
type: 'bar',
data: {
labels: [“a”, “b", “c”, ”s”],
datasets: [{
data: array
}]
}
}
But I got error when I try to traversal the List (The error line shown with Chrome debug)
var out = [{First Try=[I#6e37161d, Second Try=[I#5788d8a9}, {}];
// “Uncaught SyntaxError: Invalid or unexpected token”.
I know when directly output array with
System.out.println(array);
in java it will happen with the string like [I#6e37161d, but I don’t know how to deal with it in javascript.How can I use this array?I will be grateful if anyone can help .
Thank you very much.
You can't convert the Java object directly to a Javascript variable like you're attempting to do.
var list = #myList;
That just takes myList.toString() and attempts to set that as a literal Javascript variable. You need to serialize your Java object to JSON first, then you can parse the JSON in Javascript. Like so:
// Java controller code
String myListJson = Json.stringify(Json.toJson(myList));
// Template
#(myListJson: String)
var list = JSON.parse("#myListJson");

How to pass array from controller to javascript?

I want to pass array (2 dimension) from controller to javascript variable. I use session to pass but this not work. In javascript code I use like this:
var data = '<%= Session["LatLon"] %>';
when run project and use inspect element, there is in data :
how to pass? Can i Pass array with 2 dim with session?
When inserting the value into Session["LatLon"], save it as JSON instead of a C# string array.
string[][] mystringarr = ...
Session["LatLon"] = JsonConvert.SerializeObject(mystringarr);
And in the view use
var data = <%= Session["LatLon"] %>;
So it will generate something like
var data = [["1.0", "1.4"], ["4.6","4.8"]];
Using JSON.NET
http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_JsonConvert_SerializeObject.htm
What you are currently observing is a result of execution .ToString method of Session["LetLon"] object.
What you intent to receive is var data = [[1, 2], [3, 4]];.
So you can simply write a correct stringification of your two-dimensional array. I suggest to write simple extension method:
public static string ToJsString(this string[,] array) {
return Enumerable.Range(0, array.GetLength(0))
.Aggregate(new StringBuilder(),
(sbi, i) => sbi.AppendFormat(i == 0 ? "{0}" : ", {0}",
Enumerable.Range(0, array.GetLength(1))
.Aggregate(new StringBuilder(),
(sbj, j) => sbj.AppendFormat(j == 0 ? "{0}" : ", {0}", array[i,j]),
sbj => string.Format("[{0}]", sbj))),
sb => string.Format("[{0}]", sb));
}
In order to use it write then var data = <%= ((string[,])Session["LatLon"]).ToJsString() %>.

How to implement Dynamic data for chart in MVC?

Im new in ASP.NET MVC, im doing on my own project and i have some problems. I want to draw line chart from with data from database.
I hope you will understend me (bad english, sorry):
I have table of metals, after i click on specific one, i want to see chart that show me price of metal by date.
For example, i click on Copper;
PricePoint is my Controller, wich action shoud i call here ?
#Html.DisplayFor(modelItem => item.name)
I call DrawChart Action in PricePoint controller:
public ActionResult DrawChart()
{
return View();
}
In same controlller i create action that add data from database to json and return it.
public ActionResult Statistics(int ?id) {
// here i pull data from database to stats
return Json(stats,JsonRequestBehavior.AllowGet);
}
This is my view page where i want to show chart, DrawChart.cshtml file.
<script type="text/javascript">
$.get('#Url.Action("Statistics")', function(result){
new Morris.Line({
// ID of the element in which to draw the chart.
element: 'myfirstchart',
// Chart data records -- each entry in this array corresponds to a point on
// the chart.
data: [
result
],
// The name of the data record attribute that contains x-values.
xkey: 'year',
// A list of names of data record attributes that contain y-values.
ykeys: ['value'],
// Labels for the ykeys -- will be displayed when you hover over the
// chart.
labels: ['Value']
});
});
</script>
When i click on metal, DrawChart action return view DrawChart.cshtml, then JavaScript run Statistics function and populate data for chart, is that how this works?
I have blank page, with no result, when i type in url: http://localhost:50101/PricePoint/DrawChart
When url is next, i see json data from database:
http://localhost:50101/PricePoint/Statistics
I dont know where is problem. When i put example data in script, like this
data: [
{ year: '2008', value: 20 },
{ year: '2009', value: 10 },
{ year: '2010', value: 5 },
{ year: '2011', value: 5 },
{ year: '2012', value: 20 }
],
i see line chart as expected. Again, sorry for bad english, hope you can help me and i hope you understend my question.
I had a play with it and I managed to display the chart just fine. Here are a few things to watch out for that may be the cause of your problem:
1) your call to $.get('#Url.Action("Statistics")' is not passing in an id though you declared one on your action public ActionResult Statistics(int ?id). Considering it's nullable maybe you are prepared to serve a default set of data if no id is passed, but thought I'd mention in case that is what's affecting the logic of your database retrieval and affecting the results returned
2) I noticed that your link to the DrawChart action passed in new { id = item.ID } however this not captured on the server-side since your DrawChart action is missing the parameter, it should be something like : public ActionResult DrawChart(id). I understand this could've been for the sake of simplifying it just to post here and may not affect anything but thought I'd point it out
3) Be careful about what you are returning from the MVC action. The stats object in return Json(stats,JsonRequestBehavior.AllowGet); should be a C# array containing the properties value and year for each object in the array, so something like :
new[] {new Entry() {value = 20, year = 2008}, new Entry() {value = 10, year = 2009}};
If you just pass a string to the return Json() statement it won't work properly since it'll think it's just one long json string not a json array object.
If you want to return a string rather than an actual serialized c# collection then you can use something like : return Content(dataString, "application/json");
4) Case matters! Make sure that the json returned contains properties with names of year and value for each entry just as you declared in your morris object on the xkey and ykey values. This can be quite a subtle trap since return Json() will serialize your json objects exactly as they are declared in your classes and while the tendency in javascript code is to start variables and properties with lower-case in .Net properties are usually declared with upper-case such as public int Year { get; set; }
Conclusion:
I got it working by returning this code :
public ActionResult Statistics(int ?id) {
var data = new[] {new Entry() {value = 20, year = 2008}, new Entry() {value = 10, year = 2009}};
return Json(data,JsonRequestBehavior.AllowGet);
}
And on your Morris initialization code remove the array brackets from the data declartion so data : result and not data : [result]
Your first step to troubleshoot this is to look at what your Statistics method is returning. You can do this really easily by testing your web site in Chrome, for instance, and hitting F12 then choose the Network tab. Then Ctrl+F5 the page and find the call to the server in the results pane. Click on it and then choose Response and keep troubleshooting your method till it returns what you need.
If the data is in a wrong format and doesn't contain the keys that Morris expects Morris will throw an error saying Uncaught TypeError: Cannot read property 'match' of undefined . Keep trying till you make that go away and hopefully you should see your graph :)
PS: one last thing, I'd wrap the Morris init code in a $(document).ready() call
When i send data (values and dates) from function (manualy input), everything is ok, json file is populeted god, and i see chart, but when i send data from database, there is no chart but i see that json file is also populeted.
Here is code:
public class YearlyStat
{
public string year { get; set; }
public double value { get; set; }
}
public ActionResult Statistics(int? id)
{
//var result = db.pricepoints.Where(r => r.commodityID.Equals(id));
var items = from item in db.pricepoints
where (item.commodityID == id)
select item;
var stats = new List<YearlyStat>();
foreach (var item in items)
{
stats.Add(new YearlyStat
{
year = item.date_of_price.ToShortDateString(),
value = item.value
});
}
//but this work's
//string s = "2.2.2002";
//double v = 20.20;
//stats.Add(new YearlyStat { year = s, value = v });
//or
//stats.Add(new YearlyStat { year = "2.2.2002", value = 20.20 });
return Json(stats, JsonRequestBehavior.AllowGet);
}
Types are string and double in both cases...

Need Handlebars.js to render object data instead of "[Object object]"

I'm using Handlebars templates and JSON data is already represented in [Object object], how do I parse this data outside of the Handlebars? For example, I'm trying to populate a JavaScript variable on the page through a handlebars tag, but this doesn't work.
Any suggestions? Thank you!
EDIT:
To clarify, I'm using ExpressJS w/ Handlebars for templating. In my route, I have this:
var user = {}
user = {'id' : 123, 'name' : 'First Name'}
res.render('index', {user : user});
Then in my index.hbs template, I now have a {{user}} object. I can use {{#each}} to iterate through the object just fine. However, I'm also using Backbonejs and I want to pass this data to a View, such as this:
myView = new myView({
user : {{user}}
});
The problem is that {{user}} simply shows [Object object] in the source. If I put it in console.log I get an error that says 'Unexpected Identifier'.
When outputting {{user}}, Handlebars will first retrieve the user's .toString() value. For plain Objects, the default result of this is the "[object Object]" you're seeing.
To get something more useful, you'll either want to display a specific property of the object:
{{user.id}}
{{user.name}}
Or, you can use/define a helper to format the object differently:
Handlebars.registerHelper('json', function(context) {
return JSON.stringify(context);
});
myView = new myView({
user : {{{json user}}} // note triple brackets to disable HTML encoding
});
You can simple stringify the JSON:
var user = {}
user = {'id' : 123, 'name' : 'First Name'};
// for print
user.stringify = JSON.stringify(user);
Then in template print by:
{{{user.stringify}}};
I'm using server-side templating in node-js, but this may apply client-side as well. I register Jonathan's json helper in node. In my handler, I add context (such as addressBook) via res.locals. Then I can store the context variable client-side as follows:
<script>
{{#if addressBook}}
console.log("addressBook:", {{{json addressBook}}});
window.addressBook = {{{json addressBook}}};
{{/if}}
</script>
Note the triple curlies (as pointed out by Jim Liu).
You are trying to pass templating syntax {{ }} inside a JSON object which is not valid.
You may need to do this instead:
myView = new myView({ user : user });
In the Node Router - Stringify the response object. See below line.
response.render("view", {responseObject:JSON.stringify(object)});
In HTML Script tag - user Template literals (Template strings) and use JSON.parse.
const json= `{{{responseObject}}}`;
const str = JSON.parse(json);
Worked like a charm!
You can render the keys/values of a list or object in a Handlebars template like this:
{{#each the_object}}
{{#key}}: {{this}}
{{/each}}
If you want more control over the output formatting you can write your own helper. This one has a recursive function to traverse nested objects.
Handlebars.registerHelper('objToList', function(context) {
function toList(obj, indent) {
var res=""
for (var k in obj) {
if (obj[k] instanceof Object) {
res=res+k+"\n"+toList(obj[k], (" " + indent)) ;
}
else{
res=res+indent+k+" : "+obj[k]+"\n";
}
}
return res;
}
return toList(context,"");
});
We used handlebars for email templates and this proved useful for a user like the following
{
"user": {
"id": 123,
"name": "First Name",
"account": {
"bank": "Wells Fargo",
"sort code": " 123-456"
}
}
}
To condense (what I found to be) the most helpful answers...
JSON helper for handlebars (credit):
Handlebars.registerHelper("json", function (context) {
return JSON.stringify(context);
});
JSON helper for express-handlebars (credit and I updated to newest conventions):
app.engine(
"handlebars",
exphbs.engine({
defaultLayout: "main",
helpers: {
json: function (context) {
return JSON.stringify(context);
}
}
})
);
And then on the templating side: {{json example}}
Just improving the answer from #sajjad.
Adding a 'pre' tag will make it look a lot nicer.
<pre>
{{#each the_object}}
{{#key}}: {{this}}
{{/each}}
</pre>

Categories