I have this JSON file (truncated):
{
"** Please contact a mod by posting on the forums **": {
"tvdb_id": "257937",
"last_updated": 1341780286,
"images": {
"poster": "http://zapp.trakt.us/images/posters/17288.jpg",
"fanart": "http://zapp.trakt.us/images/fanart/17288.jpg"
}
},
"Jamies Best Ever Christmas": {
"tvdb_id": "214161",
"last_updated": 1329701153,
"images": {
"poster": "http://zapp.trakt.us/images/posters/9126.jpg",
"fanart": "http://zapp.trakt.us/images/fanart/9126.jpg"
}
},
"Kuromajo-san ga Tooru!!": {
"tvdb_id": "257914",
"last_updated": 1395775431,
"images": {
"poster": "http://zapp.trakt.us/images/posters/15640.jpg",
"fanart": "http://zapp.trakt.us/images/fanart/15640.jpg"
}
}
}
and this code:
$(".tvshow").select2({
placeholder: "Type in a TV show",
multiple: true,
maximumSelectionSize: 1,
minimumInputLength: 2,
maximumInputLength: 20,
query: function(query) {
var data = {results: []};
var value = $(".select2-input").val();
$.ajax ({
type: "GET",
url: 'shows.json',
dataType: "jsonp",
json: "callbackname",
crossDomain : true,
success: function (result) {
$.each(result, function (i, show) {
// write everything in an array
data.results.push({id: this.tvdb_id, text: this.title, poster: this.images.poster, bg: this.fanart });
console.log(this.title);
selectedTVshow = this.title;
// results = data.results;
// return array
query.callback(data);
})
},
error: function (data) {
// console.log('error');
}
})
}
})
When I search for Jamies Best Ever Christmas I want it to return the name and the respective tvdb_id and details.
In my above code you can see console.log(this.title);. This is wrong, because there is no title: value inside the JSON object. How can I get this to work and retrieve data?
Demo: http://jsfiddle.net/6pGFC/ (use first input field to get autocomplete, not second)
Thanks a lot!
There are a couple of issues in your example.
You dropbox file is not JSONP. It is JSON. (so jquery cannot parse it)
Since you are iterating over an object and not over an array with $.each the arguments passed to the function are key and value, so in your case the i is the key. (see https://api.jquery.com/jQuery.each/)
In general the searching should happen in the server side, and not on the client (especially for 5mb files)
Here is demo that has fixed (i have re-uploaded the corrected file to my dropbox) the above two problems http://jsfiddle.net/6pGFC/3/
(too slow though since it tries to display all the json)
It looks like you want to do a mapping operation to transform the data into something easier to work with. Underscore.js is a fantastic tool for this.
var mappedResults = _.map(result, function(key, value, list) {
return {name:key, tvdb_id:value.tvdb_id};
});
This will turn this:
{
"** Please contact a mod by posting on the forums **": {
"tvdb_id": "257937",
"last_updated": 1341780286,
"images": {
"poster": "http://zapp.trakt.us/images/posters/17288.jpg",
"fanart": "http://zapp.trakt.us/images/fanart/17288.jpg"
}
},
"Jamies Best Ever Christmas": {
"tvdb_id": "214161",
"last_updated": 1329701153,
"images": {
"poster": "http://zapp.trakt.us/images/posters/9126.jpg",
"fanart": "http://zapp.trakt.us/images/fanart/9126.jpg"
}
},
"Kuromajo-san ga Tooru!!": {
"tvdb_id": "257914",
"last_updated": 1395775431,
"images": {
"poster": "http://zapp.trakt.us/images/posters/15640.jpg",
"fanart": "http://zapp.trakt.us/images/fanart/15640.jpg"
}
}
}
...into this:
[
{name:"** Please contact a mod by posting on the forums **", tvdb_id:"257937"},
{name:"Jamies Best Christmas", tvdb_id:"21461"},
{name:"Kuromajo-san ga Tooru!!", tvdb_id:"257914"}
]
Once that's done, you can filter it like so:
function getMatchingIds(searchterm) {
return _.filter(mappedResults, function(entry) {
return (entry.name.indexOf(searchterm) != -1);
}
}
I should also add that jQuery has its own $.map feature that does something similar.
Related
How can I select multiple fields when using the documents.get ?
Right now I am getting the documenmt like this:
const doc = await docs.documents.get({
documentId: copiedFile.data.id,
fields: 'body/content'
});
which returns this:
"data": {
"body": {
"content": [...]
}
}
However, I need to also get the inlineObject and the only way so far I have been able to do so, is by removing the fields proeprty completely
const doc = await docs.documents.get({
documentId: copiedFile.data.id,
});
Then I get this:
"data": {
"title": "Some document title",
"body": {
"content": [...]
},
"headers": {
},
"footers": {
},
"documentStyle": {
},
"namedStyles": {
},
"lists": {
},
"revisionId": "some-long-id",
"suggestionsViewMode": "SUGGESTIONS_INLINE",
"inlineObjects": {
},
"documentId": "some-long-id"
}
But I am really only interested in data.body.content and data.inlineObjects
When selecting everything the response is many thousands of lines of json larger, which I don't want.
I have tried fields: ['body/content', 'inlineObjects'] but that only returns body.content and not the inlineObjects - also the documentation doesn't mention this syntax anywhere, it was just to experiment.
I think it doesn't return any inlineObjects when you don't have any inlineObjects in the document. To confirm if the actual format is working and the statement above is true, try using other fields where a value is confirmed to be returned such as revisionId or title.
Test:
const doc = await docs.documents.get({
documentId: copiedFile.data.id,
fields: 'body/content,inlineObjects'
});
Output:
The handlebars.js template is generated server side and returned as part of the response.
"<div>{{name}}<small style='color:#999;'><br><code>{{vafm}}</code></small><br><code>{{email}}</code></div>"
.
var t = "";
$('#UniqueId').select2({
ajax: {
url: '/search/endpoint',
dataType: 'json',
processResults: function (data) {
t = data.template;
return {
results: data.results
};
},
},
templateResult: Handlebars.compile(t),
escapeMarkup: function (m) {
return m;
}
});
Unfortunately the rendered part on select2 does not contain the values returned by the data.results
I have located the issue to this line
templateResult: Handlebars.compile(t),
since trying something like
<script>
const template = Handlebars.compile(#Html.Raw(Model.Template));
</script>
and
templateResult: template,
works as expected.
In the last example i pass the template from the model,
but not i need to pass it from the ajax response and achieve the same output.
There are multiple problems:
templateResult expects a callback function, but you are passing a compiled Handlebars template object. It's described here in the select2 docs. So, assuming that you already did the following in the right place:
var t = Handlebars.compile(...)
Then something like this would work:
templateResult: function(data) {
if (!data.id) return data.text;
return $(t({
name: 'example name',
vafm: 'example vafm',
email: 'example email'
}));
The template html must have one enclosing element, so put things in a <div></div>, for example
Your template is missing a <small> opening tag
So let's assume your server sends some JSON like the following. The template for every result is sent along and can be different for every result. Same goes for the template-specific data:
[
{
"id": 1,
"text": "Henry",
"data": {
"vafm": "1234",
"email": "henry#example.com"
},
"template": "<div>{{text}}<br><small>vafm: {{data.vafm}}</small></div><small>email: {{data.email}}</small>"
}, {
"id": 30,
"text": "Tesla Roadster",
"data": {
"price": "$200.000",
"color": "dark red"
},
"template": "<div>{{text}}<br><small>price: {{data.price}}</small></div><small>color: {{data.color}}</small>"
}
]
Together with something like this in your JavaScript, it should work:
$('#UniqueId').select2({
ajax: {
url: '/search/endpoint',
dataType: 'json',
processResults: function(data) {
/** Note: select2 expects "results" to be an array of objects, each containing
* at least "id" (becomes the value) and "text" (displayed text). I made the
* format from the server match that (plus added some more info), so that I don't
* need any conversions except for compiling the template. I do that with
* Array.prototype.map() in this case, but of course a for-loop would work too.
*/
return {
results: data.map(function(e) {
e["template"] = Handlebars.compile(e["template"]);
return e;
})
};
}
},
templateResult: function(el) {
if (!el.id) return el.text;
/* Note: "el" will be just like it came from the server, except for the
* modifications we applied in processResults. We can just pass "el" to
* the compiled template entirely and there, only pick what we need.
*/
return $(el["template"](el));
}
});
I am trying to display a tree structure in my web project.
I am using Symfony 3.4.x with jsTree v3.3.5.
PROBLEM
I can not get the tree to display when using json and ajax.
I am using an example from official jstree documentation.
If i hard code data in json format the tree is displayed without a hitch, but when i return the same json as part of ajax call - tree is not displayed (i get only one item, displayed as a folder, without a name).
I want to display all the tree nodes fully open - so loading all items is required.
CODE
my data in json format (i am using alternative json notation as per jstree documentation)
{"success":true,
"data":[
{"id":"50","parent":"#","text":"test_root"},
{"id":"51","parent":"50","text":"test_1"},
{"id":"123","parent":"51","text":"test_2"},
{"id":"73","parent":"51","text":"test_3"},
{"id":"75","parent":"51","text":"test_4"},
{"id":"76","parent":"51","text":"test_5"},
{"id":"74","parent":"51","text":"test_6"},
{"id":"78","parent":"51","text":"test_7"},
{"id":"124","parent":"51","text":"test_8"},
{"id":"77","parent":"50","text":"test_9"}
]}
using jstree
$(document).ready(function()
{
let project_tree;
project_tree = $('#file-tree-json');
project_tree.jstree({
'core':
{
'data':
{
'url': '/tree/prepare',
'dataType': 'json',
'data': function (node) {
console.log(node);
return { 'id': node.id };
},
}
},
"types": {
"root": {
"icon": "lnr lnr-home"
},
"folder": {
"icon": "lnr lnr-folder"
},
"file": {
"icon": "lnr lnr-file-empty"
}
},
"search": {
show_only_matches: true,
search_callback: function (str, node)
{
if (node.text.toLowerCase().indexOf(str) >= 0) { return true; }
}
},
"plugins": [ "types", "search" ]
});
}
code in my controller that prepares tree items data in json format
$em = $this->getDoctrine()->getManager();
$repo_file_tree = $em->getRepository('App:FileTree');
try
{
$build_my_tree_json = $repo_file_tree->prepareJsonTree($build_my_tree);
return new JsonResponse([
'success' => true,
'data' => $build_my_tree_json
]);
}
catch (\Exception $exception)
{
return new JsonResponse([
'success' => false,
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
]);
}
Other discussions on SO that are related and which i already read, but in my opinion, they did not solve the problem at hand or/and refer to jstree version that is out of date
jsTree unable to load root nodes from AJAX call
jsTree - loading subnodes via ajax on demand
JSTree - Load nodes dynamically
JStree and ajax
https://stackoverflow.com/a/22965656
CONCLUSION
What am i doing wrong?
Maybe i am overlooking some detail or technicality?
Thank you for your comments and answers.
UPDATE 1
when i am returning only data
return new JsonResponse([
$build_my_tree_json
]);
i get additional "[]" as so
[[
{"id":"50","parent":"#","text":"test_root"},
{"id":"51","parent":"50","text":"test_1"},
{"id":"123","parent":"51","text":"test_2"},
{"id":"73","parent":"51","text":"test_3"},
{"id":"75","parent":"51","text":"test_4"},
{"id":"76","parent":"51","text":"test_5"},
{"id":"74","parent":"51","text":"test_6"},
{"id":"78","parent":"51","text":"test_7"},
{"id":"124","parent":"51","text":"test_8"},
{"id":"77","parent":"50","text":"test_9"}
]]
How can one remove extra "[]" from json or reference inner array?
UPDATE 2
it works when there are returned only data about tree nodes in json format.
working example
return new JsonResponse($build_my_tree_json);
So how to make jstree work with additional data in ajax response?
There should be a way to extract all the data about tree from response that contains status and data (response as displayed in my questions CODE section).
The structure of your JSON response doesn't work well with jsTree. jsTree expects an Array of nodes. Your output structure has an array inside the data object. You should have a structure as below in your response for it to work.
[
{
"id": "50",
"parent": "#",
"text": "test_root",
"opened":true
},
{
"id": "51",
"parent": "50",
"text": "test_1"
},
{
"id": "123",
"parent": "51",
"text": "test_2"
},
...
...
]
I'm fresh to js and web dev for that matter and am looking for some help.
I'm trying to grab enough information to format and make another request. This is what i have so far
JavaScript
$( document ).ready(function(sb_shows) {
$.getJSON( "http://<myname>/api/<apikey>/?cmd=shows&callback=?", function(shows_obj) {
//$.each(shows_obj, function(key, value) {
if ( shows_obj.result == "success") {
document.write(shows_obj.result);
$.each(shows_obj.data, function(key, value) {
$.each(this.cache function(key, value) {
document.write( "<p> "+value.banner+"<p>");
});
document.write( "<p>"+value.show_name+" - "+value.tvrage_id+ "<p>");
});
}
else {
document.write("fail..");
}
});
});
JSON Sample
{
"data": {
"72023": {
"air_by_date": 0,
"cache": {
"banner": 1,
"poster": 1
},
"language": "en",
"network": "HBO",
"next_ep_airdate": "",
"paused": 0,
"quality": "SD",
"show_name": "Deadwood",
"status": "Ended",
"tvrage_id": 3267,
"tvrage_name": "Deadwood"
},
"72231": {
"air_by_date": 1,
"cache": {
"banner": 1,
"poster": 1
},
"language": "en",
"network": "HBO",
"next_ep_airdate": "2013-09-13",
"paused": 0,
"quality": "HD720p",
"show_name": "Real Time with Bill Maher",
"status": "Continuing",
"tvrage_id": 4950,
"tvrage_name": "Real Time With Bill Maher"
},
},
"message": "",
"result": "success"
}
What i'm hoping to achieve is grab the id under data (e.g. 72023 and 72231), I originally thought i'd be able to do something like
$(this).parent()
Its a object however and that doesn't appear to work
Also I'd like to be able to iterate through the sub obj's, something like below
$.each(shows_obj.data, function(key, value) {
$.each($(this).cache function(key, value) {
document.write( "<p> "+value.banner+"<p>");
});
document.write( "<p>"+value.show_name+" - "+value.cache.banner+ "<p>");
});
Any and all recomendations/suggestions will be appreciated. Please explain suggestions, i'm kinda slow:)
In your first $.each() call on the data object, your key is actually the ID number you'r e looking for. Google quickly gave me an introduction to JSON which might help you out.
As per the jQuery.each documentation the this keyword is the same as the value keyword. Your $.each($(this).cache, ...) should simply be $.each(this.cache, ...) or $.each(value.cache, ...) as you're not traversing the dom ($(..)) but passing an object to the $.each() function. Just like in the earlier case if you traverse this.cache you would have your callback be called twice:
// first
key => banner
value => 1
// second
key => poster
value => 1
If you would've just wanted the banner from the cache the thing to do would've been: value.cache.banner in your original $.each(shows_obj.data, ...)
suppose I have a config javascript file:
window.Config = {};
Config.UI = {
"Area": {},
"Layer": {},
"Sprites": {},
"Audio": {}
};
Config.UI.Area = {
"prop": {
"uuid": {
"_type": "string",
},
"frame": {
"_type": "rect",
"_value": {
"x": "0",
},
"_aka": "frame"
},
"zIndex": {
"_type": "string",
}
},
then I want use $.ajax to read this file:
$.ajax({
url:'js/config.js',
success:function (data, textStatus) {
console.log(data);
}
})
the question is how can I get some key's value in the config,by use the data $.ajax return?
like the "Config.UI" or the 'uuid' in ui.area.prop?Or can I convert them to json?
Rather than use AJAX, why not just insert a script?
var script = $('<script>');
script.attr('type', 'text/javascript');
script.attr('src', 'js/config.js');
script.bind('load', function() {
// use window.Config
});
script.appendTo('head');
icktoofay has a good suggestion, and the issue with the jQuery.ajax call looks to be a missing dataType: 'script' option which will evaluate the response and should give you object access. You might want to look into jQuery.getscript() as well.
I find it very useful and powerful to store data on the server as javascript objects and read them using Ajax. And it is very easy to do. Let me give you an example from an educational application I have written.
This is an example table of contents file (l1contents.js) that I would store on the server:
{
title : "Lesson 1",
topics : [
{name : "Topic 1", file : "l1t1data.js" },
{name : "Topic 2", file : "l1t2data.js" },
]
}
This is the javascript code I use to process the file:
$.ajax({
url : contentsFileName, // would be set to 'l1contents.js'
dataType : 'text', // yes this is correct, I want jquery to think this is text
cache : false,
success: function(data) {
var contentsObj = eval('(' + data + ')');
var lessonTitle = contentsObj.title;
for (var i = 0; i < contentsObj.topics.length; i++) {
var topic = contentsObj.topics [i];
// process topic.name and topic.file here
}
}
});
Obviously, this is simplified, but hopefully you get the idea. I simply use eval to set the object. And note that I don't even need any javascript code defining the structure of contentsObj. (I, of course, do have extensive comments defining the structure of my objects, but they are simply comments, not code.)
if your json file contains json data than you can use parseJSON() , toJSON() method.
and another solution is use eval(), this conver json data to javascript object so you can easly get a value by giving key.