I was wondering if I could pass a IEnumerable Collection into a Javascript method on the page load. So something like this...
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyAppMVC.Models.ViewModels.News.NewsIndexViewData>" %>
<div id="container">
<%= String.Format("<script type='text/javascript'>testMethod({0})</script>", Model.NewsList) %>
</div>
I realize JS is client side, just didn't know if there was any way possible to do that?
Thanks!
No, you cannot. For several reasons.
1) There is no IEnumerable in JavaScript, as you use it in .NET. There is something similar, but it is implemented completely differently. In .NET, IEnumerable just means the class provides a method, GetEnumerator(), which returns an IEnumerator (which itself only contains Current, MoveNExt, and Reset methods). In JavaScript, when you do a for iteration on an item, you are iterating over the names of its properties.
var myObj = { 'a' = 1, 'b' = 2 };
for (var name in myObj) { alert(name); } // will alert 'a', and 'b'
Even when working with JavaScript arrays, the above loop returns the index of the array element, not the actual member at that index.
2) By doing a String.Format() on your list, you wouldn't have been passing the list as an object to your JavaScript but just the ToString() result of your list. Which probably just returns "System.Collections.Generic.List`1[System.String]"
3) Unless your developing environment explicitly allows it, you can assume that passing arguments from one language into another is not going to work. Much like you can't write JavaScript inside your .NET code, you can't write .NET code in your JavaScript. These languages have different feature sets, different syntax, and are executed with completely different mechanisms - .NET is compiled, and JavaScript (generally, speaking) is interpreted (Compiled vs. Interpreted languages).
What you have to do is transform your data into a format that can be used by JavaScript. Most likely this means converting it into something called JSON. You didn't provide a lot of details as to what exactly Model.NewList is, or what your testMethod() expects as an argument. But for the sake of an example lets assume NewList is a list of strings. In that case, your JSON would look something like this:
{ 'NewList' : ['string1', 'string2', 'string3'] }
The easiest way to convert your .NET data into JSON is to use built-in libraries, such as JavaScriptSerializer:
System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string json = serializer.Serialize(Mdoel.NewList);
You can register the javascript in the code behind in the Page_Load with the following code (Note I am assuming that Model.NewsList is a string enumeration or array):
StringBuilder sb = new StringBuilder();
bool isFirst = true;
//build a comma seperated list.
foreach (string s in Model.NewsList)
{
if (isFirst)
isFirst = false;
else
sb.Append(", ");
sb.Append("'").Append(s.Replace("'", "''")).Append("'");
}
//create the javascript array
string javascript = String.Format(#"var news = [{0}];", sb);
//put the array in the generated page.
Page.ClientScript.RegisterClientScriptBlock(GetType(), "newsList", javascript);
This will put the javascript on the page accessible from other javascript functions.
Related
i have a Java ArrayList and i want to send it to the javascript for another purpose.
this is my Java ArrayList
List<String> list = new ArrayList<String>();
list.add("xxx");
list.add("yyy");
....
model.addAttribute("theList", list);
and how to send the ArrayList into javascript Array?
i'm expecting this in my javascript code
<script th:inline="javascript">
var Array = ["xxx","yyy","xxx"];
</script>
i'm truly sorry for asking this type of question again, i know there's already answered questions and duplictae questions about this case, but i don't really understand the answer. maybe some JSON things or other ways.
please show me how to write the code both in java code and javascript code.
Thanks.
As mentioned in the comments, you can use a library to serialize the object as a json string. In other words, you can convert each list element to a json object node and put all the json object nodes into an array.
What a serializer does
It takes a look at your object(s) and creates a json representation out of it/them (serializes). The opposite of a serializer is a deserializer, to convert a json string into Java objects.
Why use a library
While you could do it by hand (see below), a library such as Gson as mentioned in the comments, or jackson in the open source community has been tested on a large number of test cases and will in all likelihood be robust enough for whatever your use case is.
Example with jackson
See here.
Example "do it yourself"
Your case is very simple since your list elements are strings.
// create a string builder to build the json
StringBuilder sb = new StringBuilder();
// loop over each string in the list
for (String s : list) {
// add an initial delimiter, which will be
// removed at the end
sb.append(",");
// add a beginning quote to each term
sb.append("\"");
// add the string
sb.append(s);
// close the quote
sb.append("\"");
}
if (sb.length() > 0) {
// if there was at least one element
// in the list, remove the initial comma
sb.deleteCharAt(0);
}
// add a left square bracket
sb.insert(0, "[");
// add a right square bracket
sb.append("]");
// your string, for example
// ["one","two","three"]
String json = sb.toString();
Going back to "why use a library", the above code doesn't account for a lot of possibilities, the most obvious of which, if one of the strings in the list contains a " character it will mess everything up. Note that there are many ways to handle the above.
I hope that helps.
Scriptlet tag allows to write Java code into JSP file.
Syntax
<% java code %>
Here <%%> tags are scriplets tag and within it, we can place java code.
`<% List<String> strList = new ArrayList<String>();
strList.add("xxx");
strList.add("yyy");
strList.add("zzz");%>`
var jsArray = [<% for (int i = 0; i < strList.size(); i++) { %>"<%= strList.get(i) %>"<%= i + 1 < strList.size() ? ",":"" %><% } %>];
The output will be
var jsArray = ["xxx","yyy","zzz"];
I am using lua.vm.js to give users of my node application the ability to add features in realtime. For that I have some JS Classes that I want to give them in lua.
Now I have the problem, that some of my functions should return arrays or objects.
On Lua side it is translated to userdata. In the most cases this will work but not for a array that should be used in a ipairs/pairs function.
I now that "in ipairs" or "in pairs" is existing in lua.vm.js
The question is how can I write a function that returns an array in a way that lua.vm.js is using it as a table.
Some example Code:
on JS side:
let luaVM = require("lua.vm.js");
let l = new luaVM.Lua.State();
l._G.set("someExampleFunction", {
example: function(){
return [1,2,3,4,5];
}
});
on Lua Side:
local shouldBeTable = someExampleFunction.example()
-- this will not work because shouldBeTable is not a table
for key, value in pairs(shouldBeTable) do
print(value)
end
Is there a way how to do that or to write a helper Function like arrayToTable ?
How would I take a string (that I got from a page using jQuery's text()) such as:
var myData = "[{name:'xxx',data:[1,2,3,4,5]},{name:'yyy',data:[5,4,3,2,1]}]"; //this is a string :(
And turn it into the actual javascript object that I need, so for example:
var myObject = [{name:'xxx',data:[1,2,3,4,5]},{name:'yyy',data:[5,4,3,2,1]}];
So 'name' and 'data' will be non-dynamic variables, however names value, the data array and the length of myObject will be dynamic.
Not really sure where to start with this one. I am guessing that I will have to do a whole lot of spliting and looping, but I am open to suggestions.
Well, it can be done very easily:
var myObject = eval(myData);
However, you should be aware of the risks of the eval function. As it runs the value as a Javascript expression, it would also run any harmful code that would be in the string, so you should only use it when you have full control over what's in the string.
If you could change the format to be JSON, you could safely parse it without risks of code injection:
var myData = '[{"name":"xxx","data":[1,2,3,4,5]},{"name":"yyy","data":[5,4,3,2,1]}]';
var myObject = $.parseJSON(myData);
You mean,
var myObject = eval('(' + myData + ')');
?
EDIT
Its major con is that you can put any javascript code (not only JSON) to eval (Chrome's F12 lets anyone to exploit this). AS you are using jQuery, best choice will be
var myObject = $.parseJSON(myData);
for cross browser compatibility.
$.parseJSON
Takes a well-formed JSON string and returns the resulting JavaScript
object. Passing in a malformed JSON string may result in an exception
being thrown. For example, the following are all malformed JSON
strings:
{test: 1} (test does not have double quotes around it).
{'test': 1} ('test' is using single quotes instead of double quotes).
I am working on an app that heavily uses JavaScript. I am attempting to include some object-oriented practices. In this attempt, I have created a basic class like such:
function Item() { this.init(); }
Item.prototype = {
init: function () {
this.data = {
id: 0,
name: "",
description: ""
}
},
save: function() {
alert("Saving...");
$.ajax({
url: getUrl(),
type: "POST",
data: JSON.stringify(this.data),
contentType: "application/json"
});
}
}
I am creating Item instances in my app and then saving them to local storage like such:
Item item = new Item();
window.localStorage.setItem("itemKey", JSON.stringify(item));
On another page, or at another time, I am retriving that item from local storage like such:
var item = window.localStorage.getItem("itemKey");
item = JSON.parse(item);
item.save();
Unfortunately, the "save" function does not seem to get reached. In the console window, there is an error that says:
*save_Click
(anonymous function)
onclick*
I have a hunch that the "(anonymous function)" is the console window's way of saying "calling item.save(), but item is an anonymous type, so I am trying to access an anonymous function". My problem is, I'm not sure how to convert "var item" into an Item class instance again. Can someone please show me?
Short answer:
Functions cannot be serialized into JSON.
Explanation:
JSON is a cross-platform serialization scheme based on a subset of JS literal syntax. This being the case, it can only store certain things. Per http://www.json.org/ :
Objects: An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).
Arrays: An array is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
values: A value can be a string in double quotes, or a number, or true or false or null, or an object or an array. These structures can be nested.
Functions cannot be serialized into JSON because another non-JS platform would not be able to unserialize and use it. Consider the example in reverse. Say I had a PHP object at my server which contained properties and methods. If I serialized that object with PHP's json_encode() and methods were included in the output, how would my JavaScript ever be able to parse and understand PHP code in the methods, let alone use those methods?
What you are seeing in your resulting JSON is the toString() value of the function on the platform you're using. The JSON serilizer calls toString() on anything being serialized which isn't proper for JSON.
I believe your solution is to stop storing instances in JSON/local storage. Rather, save pertinent data for an instance which you set back to a new instance when you need.
I know this question is answered already, however I stumbled upon this by accident and wanted to share a solution to this problem, if anyone is interested.
instead of doing this:
var item = window.localStorage.getItem("itemKey");
item = JSON.parse(item);
item.save();
do something like this:
// get serialized JSON
var itemData = window.localStorage.getItem("itemKey");
//instantiate new Item object
var item = new Item();
// extend item with data
$.extend(item, JSON.parse(itemData));
// this should now work
item.save();
this will work so long as the function you are wanting to call (ie, save()) is prototypal and not an instance method (often times the case, and is indeed the case in the OP's original question.
the $.extend method is a utility method of jquery, but it is trivial to roll your own.
You cant do that, how can javascript possibly knows that item have a save function ? json doesnt allow functions as datas. just read the json spec , you cant save functions.
what you need to do is to create a serialize and deserialize method in the hash you want to stock. that will specifiy what to export and how you can "wake up" an object after parsing the corresponding json string.
You can only store plain Objects in DOMstorages (cookies, urlparams..., everything that needs [de]serialisation through JSON.stringify/JSON.parse). So what you did when sending the ajax data
ajaxsend(this.data);
also applies to string serialisation. You can only store the data, not the instance attributes (like prototype, constructor etc.). So use
savestring(JSON.stringify(item.data));
which is possible because item.data is such a plain Object. And when restoring it, you will only get that plain data Object back. In your case it's easy to reconstruct a Item instance from plain data, because your Items hold their values (only) in a public available property:
var item = new Item;
item.data = JSON.parse(getjsonstring());
Disclaimer
Not a full time time J.S. Developer, answer may have some minor bugs:
Long Boring Explanation
As mentioned by #JAAulde, your object cannot be serialized into JSON, because has functions, the technique that you are using doesn't allow it.
Many people forget or ignore that the objects that are used in an application, may not be exactly the same as saved / restored from storage.
Short & quick Answer
Since you already encapsulate the data members of your object into a single field,
you may want to try something like this:
// create J.S. object from prototype
Item item = new Item();
// assign values as you app. logic requires
item.data.name = "John Doe";
item.data.description = "Cool developer, office ladies, love him";
// encoded item into a JSON style string, not stored yet
var encodedItem = JSON.stringify(item.data)
// store string as a JSON string
window.localStorage.setItem("itemKey", encodedItem);
// do several stuff
// recover item from storage as JSON encoded string
var encodedItem = window.localStorage.getItem("itemKey");
// transform into J.S. object
item.data = JSON.parse(encodedItem);
// do other stuff
Cheers.
I know there a couple of threads similar to this one but they dont actually answer the above question.
Firts question: is it true that only primitives can be passed? (String, boolean,...)
Second question: if it is so. I have an array of String in my activiy and i need it to fill a html table in my WebView and apparently i need to use Javascript interface to do so. So the question is: How can i do that? Do I need to create a string in my activity, pass it to JS and once there recreate the array?
You could use JSON as format for your data. A simple way would be to use a lib like GSON http://code.google.com/p/google-gson/ which makes it easy to convert your ArrayList with own object-types to Strings.
Send that to your WebView via the Javascript-interface and use JSON.parse(Stringname) in JS to recreate your Array.
Best wishes,
Tim
Your option is to expose the method using strings and then you can use the JSONObject or JSONArray to parse the string and use it accordingly.
Here is what I did.
#JavascriptInterface
public void passJSON(String array, String jsonObj) throws JSONException
{
JSONArray myArray = new JSONArray(array);
JSONObject myObj = new JSONObject(jsonObj);
...
}
where array is '["string1","string2"]' and jsonObj is '{attr:1, attr2:"myName"}'
"Do I need to create a string in my activity, pass it to JS and once there recreate the array?"
That's the way i resolved it in my case ; i appended a special character to each item in the list while building up the string and later split it up in JS.
var strings = get.list(); // long string from activity.
var item1 = strings.split("=")[0];
var item2 = strings.split("=")[1];
....
Or you could go for a library