I have a Rails/backbone app I'm working on. I'd like to convert one of the attributes coming from Rails to a javascript array in backbone.
Rails is delivering the attribute as stringified JSON (I think)
$(function () {
App.initialize({ projectsJson: [{"skill":"[\"Beginner\",\"Advanced\"]"}] });
});
Then trying to convert it in backbone:
App.Models.Project = Backbone.Model.extend({
initialize: function() {
this.set({
skill: JSON.parse(this.get('skill'))
});
}
I get this error: Uncaught SyntaxError: Unexpected token B
I've tried inspecting the attribute in devtools:
var test = this.get('skill');
Which shows: "["Beginner","Advanced"]"
and:
var test = JSON.parse(this.get('skill'));
Which shows an array object with 2 elements.
If I make a new attribute:
this.set({
skillTEST: JSON.parse(this.get('skill'))
});
I can then use this new attribute and it works fine as an array. I'm very confused. Why can't I change the original attribute?
Is there a better way to do this? All I really want is that string coming from rails to be an array in backbone.
UPDATE:
I took a new approach based on meagar's answer. I decided to just not pass the array around as JSON.
the code:
JSON.stringify(new Array("Beginner","Advanced"));
produces: "["Beginner","Advanced"]"
backbones collection.create method is sending a POST request with:
{"skill":"[\"Beginner\",\"Advanced\"]"}
And I could not figure out how to fix that so I stopped using JSON.stringify.
The string "\"Beginner\",\"Advanced\"]" is not valid JSON, so no, it will not parse.
You either need to stop using JSON (it's really not apparent why you are here) or use a correctly formatted JSON string.
In the first case, you would simply pass around JavaScript arrays, and specify your configuration with an array literal:
App.initialize({ projects: [{skill: ['Beginner', 'Advanced']}] });
In the second case, you need to produce a valid JSON string in order to parse it:
App.initialize({ projectsJson: [{skill: '["Beginner","Advanced"]'}] });
In either case, you can make things far easier on yourself by choosing the correct quotes so that you don't need to escape your internal quotes, and by not needlessly wrapping your object literal keys in quotes.
Related
I am developing a Spring Boot MVC application that uses Thymeleaf templates on the front end.
I am trying to bind a HashMap from my MVC model to a JavaScript variable in one of my Thymeleaf templates. This is what has been done so far: -
In my MVC controller class, I created a HashMap that represents user skills organised into categories. The Skill class is a data object containing name and id properties: -
Map<String, List<Skill>> skillsMap = new HashMap();
I populated this map with all the category and skill information and then added it to my Model: -
model.addAttribute("skillsMap", skillsMap);
On my Thymeleaf template in a script section, I am attempting to bind this HashMap to a variable. As a second step I then attempt to retrieve one of the lists from the map and assign to a second variable: -
var skillsMapMap = [[${skillsMap}]];
var adminList = skillsMapMap.get('Admin');
When I debugged this, I could see that the HashMap was being read and an attempt was being made to bind it to my JavaScript variable: -
var skillsMapMap = {Languages=[Python, SQL, PL/SQL, Java], Databases=[MySQL, Oracle, Mongo], Editors=[Word, TextPad, Notepad]};
This looked good at first glance and I could see that it contained all my data, but it was throwing the following error: -
Uncaught Syntax Error: invalid shorthand property initializer
Having researched this, I realized that this error was caused because Java does not by default serialize the map in valid JSON format and so the attempted bind to a JavaScript variable failed. So, instead of just adding the HashMap straight to the Model as in step 2, I added some code to use Jackson to convert it into a JSON String first: -
//Populate the map with all required data then....
String objectMapper = null;
try {
objectMapper = new ObjectMapper().writeValueAsString(skillsMap);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
model.addAttribute("skillsMap", objectMapper);```
This time When I attempt to bind this to my JavaScript variable, the object looks like this when I debug in my browser: -
var skillsMapJson = {"Languages_OD":[{"id":66,"name":"SQL"},{"id":67,"name":"PL/SQL"}], etc, etc};
The JSON now looks valid, but all the quotes are escaped and it now throws a different exception: -
```Uncaught SyntaxError: Unexpected token &```
I feel that if the JSON string contained actual quotes instead of " the Map would successfully bind to my variable. I would appreciate any advice as to how to deal with this. Many thanks for reading.
EDIT: Screenshot of error added below: -
I did eventually get round this problem and so am offering a solution in case it helps anyone else. However, I feel that the solution is a bit 'hacky' and so would welcome any further answers that improve on this or offer a more elegant solution.
The problem was in the way I was trying to retrieve my map from the Model and assign to a JavaScript variable. Initially, I was trying this: -
var skillsMapRawString = [[${skillsMapJson}]];
The trouble is that this way of referencing skillsMapJson forces JavaScript to treat it as an Object and it cannot deal with the encoding issue described in the original post when attempting to deserialize it into JSON. The above line therefore threw the exception "unexpected token &".
By adding single quotes around the object reference, JavaScript is forced to treat skillsMapJson as a String and not an object: -
var skillsMapRawString = '[[${skillsMapJson}]]';
The above variable assignment now works successfully, but we still have the problem that it contains encoded quotes which prevent it being parsed to a JSON Object. This is where it feels like a bit of a hack, because I got round this by doing a global replace on the String: -
var skillsMapJSONString = skillsMapRawString.replace(/"/g, "\"");
Having replaced the encoded sections that were causing problems before, the String can now be parsed as JSON: -
var skillsMapParsed = JSON.parse(skillsMapJSONString);
And finally, I have my map of lists successfully assigned to a JavaScript variable! :)
Symbols """ and similar are HTML escapes. So your info is HTML escaped. You can unescape it back by using class org.apache.commons.text.StringEscapeUtils from the library apache.commons/commons-text. The info found at: How to unescape HTML character entities in Java?
I am afraid I don’t understand what "serializing" means. If someone can explain I’d be grateful. I am serializing a Django model in Json as explained in the Django Docs:
data = serializers.serialize("json", MyModel.objects.all())
In my HTML/JS I access the data as recommended:
{{ data|json_script:"data" }}
var myData = JSON.parse([document.getElementById('data').textContent]);
But instead of being an Object myData is a string. So I guess somehow I serialize twice or something.
I found a solution, JSON.parse works as expected on my data now:
data = json.loads(serializers.serialize("json", CoursePage.objects.child_of(self).live().public()))
But I guess I still don’t understand the meaning of "serializing" properly. The Python docs say about json.loads(s): "Deserialize s (a str instance containing a JSON document). Why do I have to deserialize before JSON.parse works? The description for JSON.parse states: "The JSON.parse() method parses a JSON string"? Which I thought Djangos serializer would gave me in the first place. I am confused.
The json_script filter is for Python objects. But serialization is already the conversion of Python objects into JSON. So effectively you're converting it twice.
In your case I wouldn't bother with that filter. Just remove the json.loads and output the data directly where you need it:
var myData = JSON.parse("{{ data|safe }}");
i know that there's so many questions about this but sorry im really confuse about this error...
i created a login page and i used ajax for the POST Request..what happens is when i used this
$.ajax({
url:'../ajax/checklogin.php',
type:'POST',
dataType:'JSON',
data:$('form').serialize(),
success: function(result){
$.post("../www/login.php",{ users_id: JSON.parse(result.users_id)}).done(window.location.href='../www/index.php');
}
});
the $.post is working but when i tried to add another field to parse i got this error.. the error is on users_active.. for some reason i dont have any idea why i got the error
$.post("../www/login.php",{ users_id: JSON.parse(result.users_id),users_active: JSON.parse(result.users_active)}).done(window.location.href='../www/index.php');
the other field are fine but the only field that gives me error is the users_active.. i even check the json array that is being returned they are valid json...
JSON.parse() takes a string and turns it into a JavScript object.
You are lucky, that JSON.parse("12345") can be converted to new Number("12345"), which is indeed an integer.
result.users_active is already a JavaScript object (or array) or maybe a String, which not represents a JSON object, so the parse will result in a syntax error as stated in https://www.w3schools.com/js/js_json_parse.asp.
I assume, you need JSON.stringify(), but to assure that, you should post some code or your result object.
https://www.w3schools.com/js/js_json_stringify.asp
Edit: Now that I have seen the object, "active" is a simple string and you can't strip the quotes. So just use users_active: result.users_active.
JSON.parse doesn't remove quotes ("), but converts your data into objects, booleans or strings - if they were valid json before (not just the values of the properties, which you have passed). See here: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
If you want to assure that you pass integers or strings (or whatever you need) to your ajax post, just use the adequate javascript functions, like parseInt() or String().
See here an example with your data:
var result = {
"id":"26",
"users_id":
"201710001",
"users_username":"123",
"users_active":"active"
};
$.post("../www/login.php", {
users_id: parseInt(result.users_id),
users_active: String(result.users_active)
}).done(window.location.href='../www/index.php');
this is a very specific request, and for that i apologise, but i am at a loss for what to do..
for a javascript project i am working on i want to be able to parse javascript with python and i found this implementation`port of the original narcissus called pynarcissus:
https://github.com/jtolds/pynarcissus
the problem for me is the information is buried in the python class structure.. something with which i am only vaguely competent.. and i want the output to be in JSON
i have tried to mine the data out but each time the JSON is invalid
my question is how would you go about doing something like this? i'd appreciate any specifics because the project contains nested classes of disparate types creating what seems to be a wholly unique problem
here are my attempts:
i took the return value for parse() and created a function that descends through the class structure returning values based on their type: 'str', 'int', 'bool', 'NoneType', 'list', 'dict', 'main.Node', 'main.Tokenizer', 'main.Object'; but the returned object is missing some properties in the classes, ie 'type', while retaining others like 'type_', also tokenizer always contains the same values
i took the output of the str function that the program prints to stdout, removed the clear and copy functions and the tokenizer: [object Object], then tried to manually add in double quotes where necessary to make the output a valid JSON object.. a few problems here, first off ignoring the tokenizer object seems like i am missing out on vital information, and the other problem was that sometimes there is "value" : "{" and sometimes there is "value" : { .. }, after completing the work the JSON was invalid
assuming the issue lied in the "value" : { .. } issue i resolved to add a new function identical the the str function but instead of printing just %s values, it would print \"%s\" where necessary.. now, i could differentiate between "value": "{" and "value" : "{ .. }" but i would have to go through and manually remove the quotes around objects.. after doing so the JSON was invalid
i've tried every copy'pasta solution for python class to json from the stacks but the nested aspect of the classes along with the changing types add complexity.. some properties lack a .dict even when the type is "class 'dict'" so the one'method'fits'all lambda solutions fail
for posterity:
once i massaged the code of pynarcissus to print json i found that the process fails on nested functions.. hilariously exactly the reason i stepped away from my homebrew method
in another thread(i) #firstfire suggested esprima and pyesprima
so i looked into the esprima suggestions, and after a bit of 2to3`ing and some more work returning valid json i got it working and so far it fits my needs perfectly
check out the issue, pull request, and fork:
issues : https://github.com/int3/pyesprima/issues/1
pr : https://github.com/int3/pyesprima/pull/2
fork : https://github.com/ghissues/pyesprima
(i) http://www.linuxquestions.org/questi....php?p=5364199
the old answer::
closed the issue and added a pull request
https://github.com/jtolds/pynarcissus/issues/6
you can check out the fork if you got here by looking for a way to parse javascript to json in python 3
https://github.com/ghissues/pynarcissus
I currently have the following javascript array:
var stuffs = ['a', 'b'];
I pass the above to the server code using jQuery's load:
var data = {
'stuffs': stuffs
};
$(".output").load("/my-server-code/", data, function() {
});
On the server side, if I print the content of request.POST(I'm currently using Django), I get:
'stuffs[]': [u'a', u'b']
Notice the [] at the prefix of the variable name stuffs. Is there a way to remove that [] before it reaches the server code?
This is default behavior in jQuery 1.4+...if you want the post to be &stuffs=a&stuffs=b instead of &stuffs[]=a&stuffs[]=b you should set the traditional option to true, like this:
$.ajaxSetup({traditional: true});
Note this affects all requests... which is usually what you want in this case. If you want it to be per-request you should use the longer $.ajax() call and set traditional: true there. You can find more info about traditional in the $.param() documentation.
When an array is submitted using a GET request, through a form or AJAX, each element is given the name of the array, followed by a pair of optionally empty square brackets. So the jQuery is generating the url http://example.com/get.php?stuff[]=a&stuff[]=b. This is the only way of submitting an array, and the javascript is following the standard.
POST requests work in exactly the same way (unless the json is sent as one long json string).
In PHP, this is parsed back into the original array, so although the query string can be a little strange, the data is recieved as it was sent. $_GET['stuff'][0] works correctly in PHP.
I'm not sure how Django parses query strings.
The [] indicates that the variable is an array. I imagine that the appending of the [] to your variable name is Python/Django's way of telling you it is an array. You could probably implement your own print function which does not show them.