Javascript explode issue - javascript

I am running an ajax query and returning JSON and one of the results is a field named image.comment e.g.
test~63~Dave Sanders~http://graph.facebook.com/998433599/picture?type=large~Dave Sanders~9 minutes ago
I'm using ~ as a separator
There maybe be multiple similar sets of data separated by ---- in image.comment so to parse the data and add it to the DOM i'm using:
if(image.comment){
html += '<div class="msgs_holder'+image.list_id+'">';
// split comment at ----
var comString = image.comment;
var comArray = comString.split("----");
var lengthArray = comArray.length,
element = null;
for (var i = 0; i < lengthArray; i++) {
element = comArray[i];
// split indiv comment at ~
var comUserString = element;
var comUserArray = comUserString.split("~");
html += '<div class="msgs_row"><div class="msgs_pic"><img src="'+comUserArray[3]+'"></div>';
html += '<div class="msgs_comment"><span class="msgs_name">'+comUserArray[2]+'</span> '+comUserArray[0]+'<br><span class="msgs_time" title="'+comUserArray[5]+'">'+comUserArray[5]+'</span></div></div>';
}
html += '</div>';
}
But the page fails to load and firefox firebug tells me: allocation size overflow
This only happens on rows of the JSON where there is data in comment column
I suspect some maybe infinite looping but can't see it
I've checked the query and it runs fine so not that
Is this the best way to explode in js?
Any ideas?
MORE INFO The reason I'm doing it this way is it's a piece of a much bigger query. Images loaded to a page with comments under each image. So I'm loading the comments into a column to be parsed for display.
Example:
Image 1 Image 2 Image 3 etc etc etc
hey i think its great!
hey back! me too
I'm not sure
MORE INFO 2 This data is taken from a MySQL query e.g
select w.img_width, w.img_height, w.prod_pic_url as preview3,
GROUP_CONCAT(ww.comment,'~', h.user_id,'~', h.name,'~',
h.live_prof_pic,'~', h.twovo_url,'~', time_ago(ww.dateadded) SEPARATOR '----') AS comment
from tableName where blah=blah
GROUP_CONCAT is the comments section mentioned above
So, to use JSON for data within data, is that possible? If so how?
Example returned data:
"preview3":"http:\/\/myurl.com\/wish_images\/production\/3578.jpg","comment":"test~63~Dave Sanders~http:\/\/graph.facebook.com\/Dave Sanders\/picture?type=large~Dave Sanders~39 minutes ago"},{"item_id":"3559","numComms":"0","numLikes":"0"... etc etc

This isn't suited for a comment, so I'll try to write what I think people are saying with respect to using JSON instead of your strings:
This:
test~63~Dave Sanders~http://graph.facebook.com/998433599/picture?type=large~Dave Sanders~9 minutes ago
Could become this:
[
{
'name': 'test',
'id': 63,
'name': 'Dave Sanders',
'url': 'http://graph.facebook.com/998433599/picture?type=large',
'when': '9 minutes ago'
// other properties
},
{
// the next one
},
{
// etc.
}
]
It may look like more work, but you could use some JSON library for php (I'm guessing, since you use the term "explode") to build the JSON on the server. Then your returned content is already in a form for your browser-based client app to use with no additional effort. I find it hard to imagine that this will be more work in the end than what you're trying to do with the string manipulation, and JSON is likely to be less brittle.

As per your updated question...
You can still use JSON for this. I think it might help you to read the JSON specification
Adding to Chris Farmer's answer, JSON can be made of Arrays as well, so you can nest your comments in the response:
var response = [
{
'name': 'test',
'id': 63,
'name: 'Dave Sanders',
'url': 'http://graph.facebook.com/998433599/picture?type=large',
'comments' : [
'comment1',
'comment2',
'comment3',
...
]
},
...
]
You can then loop through the comments like this:
// loop through the images
for ( var i = 0; i < response.length; i++ ) {
var image = response[i];
// loop through the comments
for ( var z = 0; z < response.length; z++ ) {
var comment = image.comments[z];
// insert HTML here.
}
}
Do you see how much easier and less verbose this is than your current method?
Unfortunately to make this easier for yourself in the long run you will have to re-write your backend code. However, this will teach you the benefit and power of using JSON to transport information.

Related

How do I access a JSON array in JavaScript

I have a PHP script to which I make an Ajax request, and most of it works okay, but I'm having trouble accessing an array in the data returned to the JavaScript function.
So, the PHP has a bunch of regular variables, and one array. The array, $places, has four elements, which each have three values, as so:
[["z","815","1"],["w","2813","0"],["s","1582","2"],["b","1220","5"]]
A relevant excerpt of the PHP script is:
$encoded_places = json_encode($places); // if I don't do this then I end up with a value of "Array"
$qobject->name = "$name";
$qobject->multi = "$multi";
$qobject->places= "$encoded_places";
$myJSON = json_encode($qobject);
echo $myJSON;
In the JavaScript script (using JQuery), I successfully obtain the data from the Ajax request, and I can access all the data okay, except the $places data.
$.getJSON(url, function(data, status){
var stringified = JSON.stringify(data);
var parsedObj = JSON.parse(stringified);
var x = parsedObj.name; // alert(x); // which works fine
var myArray = new Array();
myArray.push(parsedObj.places);
for(var i = 0; i < myArray.length; i++){
console.log(myArray[i]);
}
... and the console will display what I'm expecting, namely:
[["z","815","1"],["w","2813","0"],["s","1582","2"],["b","1220","5"]]
However, I'm having difficulty accessing these values. For example, supposing I try to access the "815" portion of the first element, with something like: myArray[0][1], all I end up with is "[".
I guess somehow this whole piece of data is just a string, instead of an array, but I'm not familiar enough with JavaScript to quite know how to progress.
If, for example, I do this in the JavaScript script (hoping to see 815, 2813, 1582 and 1220 in the alerts) all I'll see is the single alert with "[". (i.e. it does the loop only once, and selects the character in position 1).
for(var i = 0; i < myArray.length; i++){
console.log(myArray[i]);
alert(myArray[i][1]);
}
I would very much appreciate someone explaining:
(a) how I can access the individual elements and values in JS
(b) how I can loop through them, although presumably once it's an array and not a string then the code above should do this.
Many thanks for any assistance.
Now Resolved:
As noted by #charlietfl, below, using quotes in
$qobject->places= "$encoded_places";
screwed things up, along with using json_encode on $places. However, without removing the quotes nothing worked either way. So, removed quotes and just used json_encode on the entire structure at the end, which now works fine.
So, the original snippet of code, given above, now looks like:
$qobject->name = $name;
$qobject->multi = $multi;
$qobject->places= $places;
$myJSON = json_encode($qobject);
echo $myJSON;
Change
$qobject->places = "$encoded_places";
To
$qobject->places = $places;
And get rid of the $encoded_places = json_encode($places); so that the one call to json_encode serializes the whole structure
Try this:
$.getJSON(url, function(data, status){
var parsedObj = JSON.parse(stringified);
console.table(parsedObj.places);
console.log(parsedObj.places)[0][0];
}
In the posted code's getJSON context, data is already a JSON string. So this line is redundantly stringifying your JSON string:
var stringified = JSON.stringify(data);
stringified is now set to a literal/escaped version of the valid JSON string from the data parameter:
[[\"z\",\"815\",\"1\"],[\"w\",\"2813\",\"0\"],[\"s\",\"1582\",\"2\"],[\"b\",\"1220\",\"5\"]]
When that double-stringified value is passed to JSON.parse for the parsedObj reference, it just becomes the original JSON string again (which looks deceptively correct in an alert box).
Strings are iterable in JavaScript, so the for loop was just going over the string.

Delete multiple documents

The following code is working but extremely slow. Up till the search function all goes well. First, the search function returns a sequence and not an array (why?!). Second, the array consists of nodes and I need URI's for the delete. And third, the deleteDocument function takes a string and not an array of URI's.
What would be the better way to do this? I need to delete year+ old documents.
Here I use xdmp.log in stead of document.delete just te be safe.
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.search(b, ['unfiltered']).toArray();
for (i=0; i<fn.count(c); i++) {
xdmp.log(fn.documentUri(c[i]), "info");
};
Doing the same with cts.uris:
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.uris("", [], b);
while (true) {
var uri = c.next();
if (uri.done == true){
break;
}
xdmp.log(uri.value, "info");
}
HTH!
Using toArray will work but is most likely were your slowness is. The cts.search() function returns an iterator. So All you have to do is loop over it and do your deleting until there is no more items in it. Also You might want to limit your search to 1,000 items. A transaction with a large number of deletes will take a while and might time out.
Here is an example of looping over the iterator
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.search(b, ['unfiltered']);
while (true) {
var doc = c.next();
if (doc.done == true){
break;
}
xdmp.log(fn.documentUri(doc), "info");
}
here is an example if you wanted to limit to the first 1,000.
fn.subsequence(cts.search(b, ['unfiltered']), 1, 1000);
Several things to consider.
1) If you are searching for the purpose of deleting or anything that doesnt require the document body, using a search that returns URIs instead of nodes can be much faster. If that isnt convenient then getting the URI as close to the search expression can achieve similar results. You want to avoid having the server have to fetch and expand the document just to get the URI to delete it.
2) While there is full coverage in the JavaScript API's for all MarkLogic features, the JavaScript API's are based on the same underlying functions that the XQuery API's use. Its useful to understand that, and take a look at the equivalent XQuery API docs to get the big picture. For example Arrays vs Iterators - If the JS search API's returned Arrays it could be a huge performance problem because the underlying code is based on 'lazy evaluation' of sequences. For example a search could return 1 million rows but if you only look at the first one the server can often avoid accessing the remaining 999,999,999 documents. Similarly, as you iterate only the in scope referenced data needs to be in available. If they had to be put into an array then all results would have to be pre-fetched and put put in memory upfront.
3) Always keep in mind that operations which return lists of things may only be bounded by how big your database is. That is why cts.search() and other functions have built in 'pagination'. You should code for that from the start.
By reading the users guides you can get a better understanding of not only how to do something, but how to do it efficiently - or even at all - once your database becomes larger than memory. In general its a good idea to always code for paginated results - it is a lot more efficient and your code will still work just as well after you add 100 docs or a million.
4) take a look at xdmp.nodeUrl https://docs.marklogic.com/xdmp.nodeUri,
This function, unlike fn.documentUri(), will work on any node even if its not document node. If you can put this right next to the search instead of next to the delete then the system can optimize much better. The examples in the JavaScript guide are a good start https://docs.marklogic.com/guide/getting-started/javascript#chapter
In your case I suggest something like this to experiment with both pagination and extracting the URIs without having to expand the documents ..
var uris = []
for (var result of fn.subsequence(cts.search( ... ), 1 , 100 )
uris.push(xdmp.nodeUri(result))
for( i in uris )
xdmp.log( uris[i] )

Security issues with reading a JS array?

I'm building a website that will have a JS multi-dimensional array in a .js file in the scripts folder on the server. In the array will be video embed codes (Vimeo iframes) and additional strings for composers, players and piece names. There will about 1000 videos in the array.
var videos = [ ['embed code', 'composer name', 'player name', 'piece name'], ['embed code', 'composer name', 'player name', 'piece name']...];
There will be a search text box for users to do specific searches by composer, player, etc. A jQuery script will iterate through each inner array to find matches to the user's query and present them on the page. It will look basically like this:
function getArray(video) {
if (campyear === video[j]) {
var pos = video.indexOf(video[j]);
$('#searcharea').append('<td>' + video[(pos - pos)] + '</td><td><h3>Composer: ' + video[(pos -pos) + 1] + '</h3><br><h3>Player: ' + video[(pos - pos) + 2] + '</h3><br><h3>Piece: ' + video[(pos - pos) + 3] + '</h3></td>');
}
else
noResultCount++;
if (campyear === video[j] && count % 2 === 0)
$('#searcharea').append('</tr><tr>');
if (campyear === video[j])
count++;
if (i === videos.lenght && j === 4)
$('#searcharea').append('</table>');
if (noResultCount === videos.length * 5)
$('#searcharea').html("<h4>No results found for " + yearvalue + " " + buttonvalue + ". Not all camps have videos for every year.</h4>");
$('#searcharea').fadeIn(500);
} // End of getArray()
...
...
...
for (i = 0; i < videos.length; i++) {
for (j = 0; j < 5; j++) {
getArray(videos[i]);
}
}
I know there are security issues with the traditional SQL databases and PHP that need to be considered, but in this case should I be concerned about any threats to the data or website? My thought was the script can only read the data and print it so there wasn't much someone could do, but I'm not sure. The data isn't sensitive.
Thanks for your time.
The issue is that if someone can alter the file before it gets read in, they can inject any JavaScript code into it. One way to alter the file would be to hack your server, but they could also do it by taking over proxies that don't have to touch your machine at all. They they would have to somehow trick clients into going through the proxy, but you can't stop that from happening.
The easiest fix for this is to use a JSON file instead of a JavaScript file. JSON's syntax is very close to the syntax used for JS literals: as far as I can see from your example, the only changes you'd need to make to the file are to get rid of the "var videos =" at the start and swap your single-quotes for double-quotes. In code, exchange whatever works to this effect:
// Assume that getJS() grabs your JavaScript file
// and returns a String with the text of that file.
var videoCode = getJS();
eval(videoCode);
...for something that works like this:
// Assume that getJSONData() grabs your JSON
// and returns a String with the text of the file.
jsonData = getJSONData();
var videos = JSON.parse(jsonData);
Note that we're using JSON.parse (which has polyfills for old browsers) instead of eval. We do this because that puts the code through a dedicated JSON parser instead of a JavaScript one. JSON doesn't know how to deal with code, so even if an attacker tries to inject code by changing the file, the changed code won't work, because JSON won't know what to do with it. Obviously you don't want your app to just stop in the middle, but it's better than letting the attacker take over.

How to read json data in typeahead.js?

I want to read my data in JSON file then using it with typeahead.js here's a link
if some one write any word like EnglishWords [Best] it will show him/she list all of the words that started with best or like best and select the word then show the description of the word
but I have no any idea because I am new in javascript and json thanks a lot :)
here's example of my json data file
var Words = [
{"EnglishWords":"Best","Description":"an expression of good some this"},
{"EnglishWords":"Best wishes","Description":"an expression of hope"},
{"EnglishWords":"Application","Description":"Computing a program or piece of software"},
-
-
-
-
-
-
];
It looks like you have two separate things going on. One of is the autocomplete and the other some kind of word/phrase definition?
typeahead.js is only going to address the first part but it seems easy enough. Adapting the example from the github page, you'd want something like:
$('input.englishwords').typeahead({
name: 'words',
local: ['application', 'best', 'best wishes']
});
EDIT:
You'll have to parse your JSON object into an array or into an object that typeahead wants. Something like:
var typeList = [];
for (var i = 0; i < Words.length; i++) {
typeList.push(Words[i].EnglishWords);
}
then:
$('input.englishwords').typeahead({
name: 'words',
local: typeList
});

How to display raw JSON data on a HTML page [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
JSON pretty print using JavaScript
I'd like to display my raw JSON data on a HTML page just as JSONview does. For example, my raw json data is:
{
"hey":"guy",
"anumber":243,
"anobject":{
"whoa":"nuts",
"anarray":[
1,
2,
"thr<h1>ee"
],
"more":"stuff"
},
"awesome":true,
"bogus":false,
"meaning":null,
"japanese":"明日がある。",
"link":"http://jsonview.com",
"notLink":"http://jsonview.com is great"
}
It comes from http://jsonview.com/, and what I want to achieve is like http://jsonview.com/example.json if you use Chrome and have installed the JSONView plugin.
I've tried but failed to understand how it works. I'd like to use a JS script (CSS to highlight) to custom format my raw JSON data which is retrieved by ajax and finally put it on a HTML page in any position like into a div element. Are there any existing JS libraries that can achieve this? Or how to do it?
I think all you need to display the data on an HTML page is JSON.stringify.
For example, if your JSON is stored like this:
var jsonVar = {
text: "example",
number: 1
};
Then you need only do this to convert it to a string:
var jsonStr = JSON.stringify(jsonVar);
And then you can insert into your HTML directly, for example:
document.body.innerHTML = jsonStr;
Of course you will probably want to replace body with some other element via getElementById.
As for the CSS part of your question, you could use RegExp to manipulate the stringified object before you put it into the DOM. For example, this code (also on JSFiddle for demonstration purposes) should take care of indenting of curly braces.
var jsonVar = {
text: "example",
number: 1,
obj: {
"more text": "another example"
},
obj2: {
"yet more text": "yet another example"
}
}, // THE RAW OBJECT
jsonStr = JSON.stringify(jsonVar), // THE OBJECT STRINGIFIED
regeStr = '', // A EMPTY STRING TO EVENTUALLY HOLD THE FORMATTED STRINGIFIED OBJECT
f = {
brace: 0
}; // AN OBJECT FOR TRACKING INCREMENTS/DECREMENTS,
// IN PARTICULAR CURLY BRACES (OTHER PROPERTIES COULD BE ADDED)
regeStr = jsonStr.replace(/({|}[,]*|[^{}:]+:[^{}:,]*[,{]*)/g, function (m, p1) {
var rtnFn = function() {
return '<div style="text-indent: ' + (f['brace'] * 20) + 'px;">' + p1 + '</div>';
},
rtnStr = 0;
if (p1.lastIndexOf('{') === (p1.length - 1)) {
rtnStr = rtnFn();
f['brace'] += 1;
} else if (p1.indexOf('}') === 0) {
f['brace'] -= 1;
rtnStr = rtnFn();
} else {
rtnStr = rtnFn();
}
return rtnStr;
});
document.body.innerHTML += regeStr; // appends the result to the body of the HTML document
This code simply looks for sections of the object within the string and separates them into divs (though you could change the HTML part of that). Every time it encounters a curly brace, however, it increments or decrements the indentation depending on whether it's an opening brace or a closing (behaviour similar to the space argument of 'JSON.stringify'). But you could this as a basis for different types of formatting.
Note that the link you provided does is not an HTML page, but rather a JSON document. The formatting is done by the browser.
You have to decide if:
You want to show the raw JSON (not an HTML page), as in your example
Show an HTML page with formatted JSON
If you want 1., just tell your application to render a response body with the JSON, set the MIME type (application/json), etc.
In this case, formatting is dealt by the browser (and/or browser plugins)
If 2., it's a matter of rendering a simple minimal HTML page with the JSON where you can highlight it in several ways:
server-side, depending on your stack. There are solutions for almost every language
client-side with Javascript highlight libraries.
If you give more details about your stack, it's easier to provide examples or resources.
EDIT: For client side JS highlighting you can try higlight.js, for instance.
JSON in any HTML tag except <script> tag would be a mere text. Thus it's like you add a story to your HTML page.
However, about formatting, that's another matter. I guess you should change the title of your question.
Take a look at this question. Also see this page.

Categories