I aam trying to GET an array from a JSON file using JQuery's ajax methods. Specifically, I want to make the ajax request on document load and use the acquired data in other functions.
Here is my code:
$(document).ready(function() {
getJSON();
clickEvents();
});
function getJSON() {
$.getJSON('goods.js', function(data) {
crazyFun(data.Goods);
addScores(data.karma);
});
}
}
function addScores(karma) {
$('#karmaYinYangScore').append(karma[0].karmaYinYangScore);
$('#KarmaGiveScore').append(karma[0].KarmaGiveScore);
$('#KarmaTakeScore').append(karma[0].KarmaTakeScore);
$('#ItemsGiveScore').append(karma[0].ItemsGiveScore);
$('#ItemsTakeScore').append(karma[0].ItemsTakeScore);
}
function crazyFun(Goods) {
for (var i = 0; i < Goods.length; i++) {
var alpha= $('#template').clone();
alpha.removeAttr('id');
alpha.find('div.picture').attr('id', Goods[i].picture);
alpha.find('h2').html(Goods[i].header);
alpha.find('p').html(Goods[i].text);
alpha.find('div.notification').attr('id', Goods[i].notification);
$('#repeater').append(alpha);
}
}
karma and Goods are the name of the arrays in the JSON file.
What am I doing wrong?
Here is my JSON array for karma:
{
Goods : [{
"header": "Apple",
"text": "hi"
"picture": "appleImage",
"notification": "appleNote"
}, {
"header": "Pear",
"text": "hi",
"picture": "pearImage",
"notification": "pearNote"
}, {
"header":hi",
"picture": "bananaImage",
"notification": "bananaNote"
}, {
"header": "Dog",
"text": "hi",
"picture": "dogImage",
"notification": "dogNote"
}, {
"header": "Cat",
"text": "hi",
"picture": "catImage",
"notification": "catNote"
}, {
"header": "Snake",
"text": "hi",
"picture": "snakeImage",
"notification": "snakeNote"
}],
karma : [{
"karmaYinYangScore": "200",
"KarmaGiveScore": "40",
"KarmaTakeScore": "99",
"ItemsGiveScore": "20",
"ItemsTakeScore": "77"
}];
}
I can only guess what your data looks like, but since you said "karma and Goods are the name of the arrays", I'm going to assume we're talking about something like this:
{
karma: [{
karmaYinYangScore:'some value',
KarmaGiveScore:'some value',
KarmaTakeScore:'some value',
ItemsGiveScore:'some value',
ItemsTakeScore:'some value'
}
],
Goods: ['more','array','values']
}
If that's the case, we've got a few issues in your code.
First, getJSON returns one data result, so you should be referencing only that data returned.
function getJSON() {
$.getJSON('goods.js', function( data ) {
crazyFun( data.Goods ); // reference Goods array from data response
addScores( data.karma ); // reference karma array from data response
});
}
Then, your .addScores() function doesn't accept a parameter. You need some reference to receive the array being passed.
// Reference to the array being passed to the function
// ---------------v
function addScores( karma ) {
$('#karmaYinYangScore').append(karma[0].karmaYinYangScore);
$('#KarmaGiveScore').append(karma[0].KarmaGiveScore);
$('#KarmaTakeScore').append(karma[0].KarmaTakeScore);
$('#ItemsGiveScore').append(karma[0].ItemsGiveScore);
$('#ItemsTakeScore').append(karma[0].ItemsTakeScore);
}
These are the only errors I see. Beyond that, the solution depends on the actual data structure of the response.
According to jQuery's documentation on the getJSON function (http://api.jquery.com/jQuery.getJSON/), your callback's parameters appear to be misleading. Your callback...
function(Goods, karma) {
crazyFun(Goods);
addScores(karma);
}
...appears to be expecting the arrays of data to be passed to it automatically, but jQuery actually passes the whole JSON result as the first parameter, and the status of your request as the second parameter, regardless of how the JSON is structured. Your callback should probably look more like this:
function(json, status) {
crazyFun(json.Goods);
addScores(json.karma);
}
This assumes that your JSON is well formed, and that the "Goods" and "karma" properties are properties of the root object. You may need to modify the callback if your JSON is structured differently.
Related
When I try to parse this JSON (Discord webhook):
{
"content": "this `supports` __a__ **subset** *of* ~~markdown~~ 😃 ```js\nfunction foo(bar) {\n console.log(bar);\n}\n\nfoo(1);```",
"embed": {
"title": "title ~~(did you know you can have markdown here too?)~~",
"description": "this supports [named links](https://discordapp.com) on top of the previously shown subset of markdown. ```\nyes, even code blocks```",
"url": "https://discordapp.com",
"color": 16324973,
"timestamp": "2018-12-18T09:22:12.841Z",
"footer": {
"icon_url": "https://cdn.discordapp.com/embed/avatars/0.png",
"text": "footer text"
},
"thumbnail": {
"url": "https://cdn.discordapp.com/embed/avatars/0.png"
},
"image": {
"url": "https://cdn.discordapp.com/embed/avatars/0.png"
},
"author": {
"name": "author name",
"url": "https://discordapp.com",
"icon_url": "https://cdn.discordapp.com/embed/avatars/0.png"
},
"fields": [
{
"name": "🤔",
"value": "some of these properties have certain limits..."
},
{
"name": "😱",
"value": "try exceeding some of them!"
},
{
"name": "🙄",
"value": "an informative error should show up, and this view will remain as-is until all issues are fixed"
},
{
"name": "<:thonkang:219069250692841473>",
"value": "these last two",
"inline": true
},
{
"name": "<:thonkang:219069250692841473>",
"value": "are inline fields",
"inline": true
}
]
}
}
Using this code:
var parsed = JSON.parse(req.body)
I get this error:
SyntaxError: Unexpected token o in JSON at position 1
But if I use a website such as
https://jsonformatter.curiousconcept.com
To validate the JSON, it says the JSON is valid.
What is wrong here?
UPDATE
I'm using an express server to simulate discord server, so it sends web hooks to the express server instead, I get the JSON using req.body.
This happens because JSON is a global object (it's the same object where you read the method parse!), so when you invoke JSON.parse(JSON) javascript thinks you want to parse it.
The same thing doesn't happen when you pass the variable to the validator, because it will be assigned to a local variable:
let JSON = "{}";
validate(JSON);
function(x) {
JSON.parse(x); // here JSON is again your global object!
}
EDIT
According to your updated question, maybe it happens because you already use bodyParser.json() as middleware, and when you use it, req.body is already an object and you don't need to parse it again.
Trying to parsing an already parsed object will throw an error.
It would be something like without using JSONStream:
http.request(options, function(res) {
var buffers = []
res
.on('data', function(chunk) {
buffers.push(chunk)
})
.on('end', function() {
JSON.parse(Buffer.concat(buffers).toString())
})
})
For using it with JSONStream, it would be something like:
http.request(options, function(res) {
var stream = JSONStream.parse('*')
res.pipe(stream)
stream.on('data', console.log.bind(console, 'an item'))
})
(OR)
Here is the Some Steps for this issue..
You Can use lodash for resolving this.
import the lodash and call unescape().
const _ = require('lodash');
let htmlDecoder = function(encodedStr){
return _.unescape(encodedStr);
}
htmlDecoder(JSON);
I am trying to get the filter result out from the json where the matched is true.
{
"cat": [
{
"volume": "one",
"category": [
{
"name": "Alpha",
"matched": true
},
{
"name": "Gamma",
"matched": false
}
]
},
{
"volume": "two",
"category": [
{
"name": "Beta",
"matched": false
},
{
"name": "Treta",
"matched": true
},
{
"name": "Neutral",
"matched": false
}
]
},
{
"volume": "three",
"category": [
{
"name": "Retro",
"matched": false
},
{
"name": "Jazz",
"matched": true
},
{
"name": "Rock",
"matched": false
},
{
"name": "Soft",
"matched": false
}
]
}
]
}
Used Javascript filter
var jsonwant = jsonusing.cat.filter(function(e){
return e.category.filter(function(e1){
return e1.matched === true;
});
});
Js Fiddle for same
http://jsfiddle.net/xjdfaey3/
Result Should Come as
"cat": [
{
"volume": "one",
"category": [
{
"name": "Alpha",
"matched": true
}
]
},
{
"volume": "two",
"category": [
{
"name": "Treta",
"matched": true
}
]
},
{
"volume": "three",
"category": [
{
"name": "Jazz",
"matched": true
}
]
}
]
but it is returning entire object.
I like the answer from #dsfq. It is probably as good as you will get using simple Javascript without a library. But I work on a JS functional programming library, Ramda, and that offers tools to make problems like this more tractable. Here is a one-line function to do this using Ramda:
evolve({'cat': map(evolve({category: filter(whereEq({'matched': true}))}))});
Explanation
whereEq accepts a template object and returns a predicate function that will take another object and check whether this new object has the same values for the keys of the template object. We pass it {'matched': true} so it accepts an object and checks whether this object has a 'matched' property with the value true. (This is oversimplified a bit. The function, like most Ramda functions actually is automatically curried, and would accept the test object initially, but since we don't supply one, it simply returns a new function that is expecting it. All the functions below act the same way, and I won't mention it for each.)
The function generated by whereEq is passed to filter. Filter accepts a predicate function (one which tests its input and returns true or false) and returns a function which accepts a list of objects, returning a new lists consisting of only those ones for which the function returned true.
Using this, we create an object to pass to evolve. This function accepts a configuration object that maps property objects to transformation functions. It returns a new function that accepts an object and returns a copy of it, except where transformation functions have been declared in the configuration object. There it returns the result of running that transformation against the data from the object. In our case, it will run the filter we've just built against the category property.
The function generated here is passed to map, which takes a function and returns a new function that accepts a list and returns the result of applying that function to every element of the list. Here that will end up being the collection of volumes.
Now the result of this map call is passed to evolve again for the property 'cat' of the outermost object. This is the final function. You can see it in action in the Ramda REPL.
I'm not trying to claim that this is inherently better. But tools that help you look at problems from a higher level of abstraction often let you write more succinct code.
You also need to modify internal category array after filtering:
var jsonwant = jsonusing.cat.filter(function(e){
return (e.category = e.category.filter(function(e1){
return e1.matched === true;
})).length;
});
Note, that this will modify original object too.
UPD. In order to preserve original structure one more mapping step is needed to create new array:
var jsonwant = jsonusing.cat.map(function(e) {
return {
volume: e.volume,
category: e.category.filter(function(e1){
return e1.matched === true;
})
};
})
.filter(function(e) {
return e.category.length;
});
I'm trying to add data to the end of an observable array but it's just not working as expected. I bet it is something minor but I just can't get my head around it.
What I am doing:
self.businesses = ko.observableArray();
function Business(business) {
var self = this;
self.BusinessID = ko.observable(business.BusinessID );
self.Type = ko.observable(business.Type);
self.Location = ko.observable(business.Location);
}
/*ajax get array of businesses as follows:
[
{
"$id": "1",
"BusinessID ": 62,
"Type": "Data",
"Location": "Data"
},
{
"$id": "2",
"BusinessID ": 63,
"Type": "Data",
"Location": "Data"
},
{
"$id": "3",
"BusinessID ": 64,
"Type": "Data",
"Location": "Data",
} ]
*/
var mappedBusinesses = $.map(data, function (business) { return new Business(business) });
self.businesses(mappedBusinesses);
This all works as expected and the obersablearray is populated.
However if I go to add another business, it wont work. For example, if I call the ajax that returns this (as newBusiness):
{
"$id": "1",
"BusinessID ": 68,
"Type": "Data",
"Location": "Data"
}
and I do:
self.businesses().push(newBusiness);
It adds to the array as an "Object" not a Business. So I thought I would do:
var bus = $.map(newBusiness, function (business) { return new Business(business) });
self.businesses().push(bus);
But I get the error in the JS console "Uncaught TypeError: Cannot read property 'BusinessID' of null
So I made a new var and added the brackets: [] in and it adds to the observable array but not as a "Business" object but rather as an "Array[1]" object at the end and this doesn't function as per the others. Code as follows:
var newBus = {
BusinessID: newBusiness.BusinessID,
Type: newBusiness.Type,
Location: newBusiness.Location
}
var bus = $.map(newBus, function (business) { return new Business(business) });
self.businesses().push(bus);
As mentioned this adds to the observable array but doesn't actually add as a "business" object but rather as an "array[1]" object.
I bet it's something so basic but just can't get it working!
Argh I knew it would be simple!
It was posting the whole array to the ObservableArray...not just the object.
The fix:
self.businesses.push(newBusiness[0])
Had to add the [0] in to get it to push the actual data into the array, not the object!
Thanks for the answers!
You're evaluating the array with your push:
self.businesses().push(newBusiness);
Observable Arrays have their own array functions, you should just do this (no parens):
self.businesses.push(newBusiness);
See this page: http://knockoutjs.com/documentation/observableArrays.html
I am using backbone's fetch method to retrieve a set of JSON from the server. Inside the fetch call, I have a success callback that correctly assigns attributes to a model for each object found.
var foo = assetCollection.fetch({
reset: true,
success: function(response){
var data = response.models[0].attributes.collection.items;
data.forEach(function(data){
assetCollection.add([
{src_href: data.data[0].value,
title: data.data[1].value
}
]);
});
console.log(assetCollection.models)
}
})
Right now I am working with a static set of JSON that has two objects. However, logging assetCollection.models returns three objects: the first is the initial server JSON response, while the next two are correctly parsed Backbone models.
How do I keep Backbone from adding the first object (the entire response from the server) to its set of models, and instead just add the two JSON objects that I am interested in?
The JSON object returned from the server is as follows:
{
"collection": {
"version": "1.0",
"items": [
{
"href": "http://localhost:8080/api/assets/d7070f64-9899-4eca-8ba8-4f35184e0853",
"data": [
{
"name": "src_href",
"prompt": "Src_href",
"value": "http://cdn.images.express.co.uk/img/dynamic/36/590x/robin-williams-night-at-the-museum-498385.jpg"
},
{
"name": "title",
"prompt": "Title",
"value": "Robin as Teddy Roosevelt"
}
]
},
{
"href": "http://localhost:8080/api/assets/d7070f64-9899-4eca-8ba8-4f35184e0853",
"data": [
{
"name": "src_href",
"prompt": "Src_href",
"value": "http://b.vimeocdn.com/ts/164/830/164830426_640.jpg"
},
{
"name": "title",
"prompt": "Title",
"value": "Mrs. Doubtfire"
}
]
}
]
}
}
You should modufy collection.
Probably you should change parse method:
yourCollection = Backbone.Collection.extend({
parse: function(data) {
return data.models[0].attributes.collection.items;
}
})
When you use fetch Backbone parse result and add all elements what you return in parse.
I'm using REST adapter, when I call App.Message.find() Ember.js makes call to the /messages to retrieve all messages and expect to see JSON structure like this:
{
"messages": [] // array contains objects
}
However API I have to work with response always with:
{
"data": [] // array contains objects
}
I only found the way1 to change namespace or URL for the API. How to tell REST adapter to look for data instead of messages property?
If this is not possible how to solve this problem? CTO said we can adapt API to use with REST adapter as we want, but from some reason we can't change this data property which will be on each response.
Assuming you are ok with writing your own adapter to deal with the difference, in the success callback you can simply modify the incoming name from "data" to your specific entity -in the case above "messages"
I do something like this to give you and idea of what if possible in a custom adapter
In the link below I highlighted the return line from my findMany
The json coming back from my REST api looks like
[
{
"id": 1,
"score": 2,
"feedback": "abc",
"session": 1
},
{
"id": 2,
"score": 4,
"feedback": "def",
"session": 1
}
]
I need to transform this before ember-data gets it to look like this
{
"sessions": [
{
"id": 1,
"score": 2,
"feedback": "abc",
"session": 1
},
{
"id": 2,
"score": 4,
"feedback": "def",
"session": 1
}
]
}
https://github.com/toranb/ember-data-django-rest-adapter/blob/master/packages/ember-data-django-rest-adapter/lib/adapter.js#L56-57
findMany: function(store, type, ids, parent) {
var json = {}
, adapter = this
, root = this.rootForType(type)
, plural = this.pluralize(root)
, ids = this.serializeIds(ids)
, url = this.buildFindManyUrlWithParent(store, type, ids, parent);
return this.ajax(url, "GET", {
data: {ids: ids}
}).then(function(pre_json) {
json[plural] = pre_json; //change the JSON before ember-data gets it
adapter.didFindMany(store, type, json);
}).then(null, rejectionHandler);
},