Unable to retrieve JSON array with AngularJS $resource - json

I've been trying retrieve values from JSON and so far, been unsuccessful. It does get called on the front-end when I refresh the page, but the information is not passing to the next method. I think the issue might be down to the promises.push... line, as I've tried to debug the method underneath and the information is not being passed on at all.
AngularJS:
var promises = [];
promises.push(SpringDataRestService.get({"collection": "subjects"}).$promise);
// Require each of these queries to complete before continuing
$q.all(promises).then(function (data) {
// Grab the first result
$scope.available = data[0].subjects;
$scope.selected = [];
// If this is an update, get the second result in set
if (data.length > 1) {
// For each permission that is assigned to this role, add ID (name) to selected
for (var i = 0; i < data[1].data.subjects.length; i++) {
var perm = data[1].data.subjects[i];
$scope.selected.push(perm.name);
}
}
$scope.tableEditOptions = new NgTableParams({}, {
dataset: $scope.available
});
$scope.available, 'name');
}).catch(function (data) {
// ERROR
});
JSON:
[
{
"name": "FWGWG",
"description": "WGWGWG",
"lockId": 0
},
{
"name": "QFQFQF",
"description": "QFQFQFQ",
"lockId": 0
}
]
I'm confident as well my for loop is wrong due to assigning the values as well, since I don't think it should be data.subjects, but I understand these threads are only 1 issue per question. Any help would be greatly appreicated.

Use the query method for arrays:
var promise = SpringDataRestService.query({"collection": "subjects"}).$promise;
promise.then(function (dataArr) {
console.log(dataArr);
//...
}).catch(function (errorResponse) {
console.log(errorResponse);
});
With the REST services, the get method returns a JavaScript object and the query method returns a JavaScript array.
From the Docs:
$resource Returns
A resource "class" object with methods for the default set of resource actions optionally extended with custom actions. The default set contains these actions:
{
'get': {method: 'GET'},
'save': {method: 'POST'},
'query': {method: 'GET', isArray: true},
'remove': {method: 'DELETE'},
'delete': {method: 'DELETE'}
}
...
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.
For more information, see
AngularJS $resource Service API Reference

Related

Iterating through json api dictionary field

Is there a way to iterate through an api using an ajax "GET" method on a given url? I have a series of ranks with data contained therein and I'm trying to use a for loop to access the data. The api is structured as such:
{
"top_5":{
"rank_1": [
123,
456,
],
"rank_2": [
123,
456,
],
}
}
And my ajax call in the html is written like so:
<script>
for (let i = 1; i < 6; i++) {
$.ajax({
method: "GET",
url: '/refunds/api',
success: function(data){
metric = data.top_5.rank_1
myDiv = 'myChart'+i
barChart()
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
}
</script>
The loop works for generating a unique div id, but now I'm stuck trying to engineer the metric variable so that is dynamic and iterates to data.top_5.rank_i+1 on each loop. I think I need to use the map function, but I'm not sure how'd I'd implement it. Any help would be appreciated.
I believe
metric = data.top_5["rank_"+i]
could work. It's called bracket notation, can be useful when you need to access dicts/objects with variable names.
metric = data["top_5"]["rank_"+i]
would also work for example.
metric = data.top_5."rank_"+i
doesn't work because the interpreter doesn't know what to do with that. For the dot notation it needs it to be typed out like
metric = data.top_5.rank_0
Additionally I noticed you are making 6 api calls where I belive you can make only 1 api call (should improve performance). This would be the modification for that:
<script>
$.ajax({
method: "GET",
url: '/refunds/api',
success: function(data){
for (let i = 1; i < 6; i++) {
metric = data.top_5["rank_"+i];
myDiv = 'myChart'+i;
barChart();
}
},
error: function(error_data){
console.log("error");
console.log(error_data);
}
});
</script>

How to access the contents of a JSON file without a key?

Basically, I am setting up a web server via Node.js and Express (I am a beginner at this) to retrieve data by reading a JSON file.
For example, this is my data.json file:
[{
"color": "black",
"category": "hue",
"type": "primary"
},
{
"color": "red",
"category": "hue",
"type": "primary"
}
]
I am trying to retrieve all of the colors by implementing this code for it to display on localhost:
router.get('/colors', function (req, res) {
fs.readFile(__dirname + '/data.json', 'utf8', function (err, data) {
data = JSON.parse(data);
res.json(data); //this displays all of the contents of data.json
})
});
router.get('/colors:name', function (req, res) {
fs.readFile(__dirname + '/data.json', 'utf8', function (err, data) {
data = JSON.parse(data);
for (var i = 0; i < data.length; i++) {
res.json(data[i][1]); //trying to display the values of color
}
})
});
How do I go about doing this?
What you are trying to do is actually pretty simple once you break it into smaller problems. Here is one way to break it down:
Load your JSON data into memory for use by your API.
Define an API route which extracts only the colours from your JSON data and sends them to the client as a JSON.
var data = [];
try {
data = JSON.parse(fs.readFileSync('/path/to/json'));
} catch (e) {
// Handle JSON parse error or file not exists error etc
data = [{
"color": "black",
"category": "hue",
"type": "primary"
},
{
"color": "red",
"category": "hue",
"type": "primary"
}
]
}
router.get('/colors', function (req, res, next) {
var colors = data.map(function (item) {
return item.color
}); // This will look look like: ["black","red"]
res.json(colors); // Send your array as a JSON array to the client calling this API
})
Some improvements in this method:
The file is read only once synchronously when the application is started and the data is cached in memory for future use.
Using Array.prototype.map Docs to extract an array of colors from the object.
Note:
You can structure the array of colors however you like and send it down as a JSON in that structure.
Examples:
var colors = data.map(function(item){return {color:item.color};}); // [{"color":"black"},{"color":"red"}]
var colors = {colors: data.map(function(item){return item.color;})} // { "colors" : ["black" ,"red"] }
Some gotchas in your code:
You are using res.json in a for loop which is incorrect as the response should only be sent once. Ideally, you would build the JS object in the structure you need by iterating over your data and send the completed object once with res.json (which I'm guessing internally JSON.stringifys the object and sends it as a response after setting the correct headers)
Reading files is an expensive operation. If you can afford to read it once and cache that data in memory, it would be efficient (Provided your data is not prohibitively large - in which case using files to store info might be inefficient to begin with)
in express, you can do in this way
router.get('/colors/:name', (req, res) => {
const key = req.params.name
const content = fs.readFileSync(__dirname + '/data.json', 'utf8')
const data = JSON.parse(content)
const values = data.reduce((values, value) => {
values.push(value[key])
return values
}, [])
// values => ['black', 'red']
res.send(values)
});
and then curl http://localhost/colors/color,
you can get ['black', 'red']
What you're looking to do is:
res.json(data[i]['color']);
If you don't really want to use the keys in the json you may want to use the Object.values function.
...
data = JSON.parse(data)
var values = []
for (var i = 0; i < data.length; i++) {
values.push(Object.values(data[i])[0]) // 0 - color, 1 - category, 2 - type
}
res.json(values) // ["black","red"]
...
You should never use fs.readFileSync in production. Any sync function will block the event loop until the execution is complete hence delaying everything afterwords (use with caution if deemed necessary). A few days back I had the worst experience myself and learnt that in a hard way.
In express you can define a route with param or query and use that to map the contents inside fs.readFile callback function.
/**
* get color by name
*
* #param {String} name name of the color
* #return {Array} array of the color data matching param
*/
router.get('/colors/:name', (req, res) => {
const color = req.params.name
const filename = __dirname + '/data.json';
fs.readFile('/etc/passwd', 'utf8', (err, data) => {
if(err){
return res.send([]); // handle any error returned by readFile function here
}
try{
data = JSON.parse(data); // parse the JSON string to array
let filtered = []; // initialise empty array
if(data.length > 0){ // we got an ARRAY of objects, right? make your check here for the array or else any map, filter, reduce, forEach function will break the app
filtered = data.filter((obj) => {
return obj.color === color; // return the object if the condition is true
});
}
return res.send(filtered); // send the response
}
catch(e){
return res.send([]); // handle any error returned from JSON.parse function here
}
});
});
To summarise, use fs.readFile asynchronous function so that the event loop is not clogged up. Inside the callback parse through the content and then return the response. return is really important or else you might end up getting Error: Can't set headers after they are sent
DISCLAIMER This code above is untested but should work. This is just to demonstrate the idea.
I think you can’t access JSON without key. You can use Foreach loop for(var name : object){} check about foreach it may help you

Backbone: fetching from URL in router gets undefined, but it works when collection gets JSON from a variable

From a JSON stored in a variable I can get the name of the current id from a router function called show: function(id). However, when I fetch collection from an URL instead of using a JSON variable I get an undefined TypeError.
console.log(this.collection.get(id).get('name'));
What I have seen is that when I use a JSON variable the show function works fine, but when I fetch from URL, show function executes after fetch succeed.
What I am doing wrong? Why fetching from URL gets undefined? How can I make it work?
The following code is fictional, it only shows the relevant part of my code. See the two cases at the end of the code block.
jsFiddle here
// Data 1 with variable
var heroes = [
{"id": "1", "name": "Batman"},
{"id": "2", "name": "Superman"},
];
// Data 2 from url: http://example.com/heroes.json
[
{"id": "1", "name": "Batman"},
{"id": "2", "name": "Superman"},
];
HeroesCollection = Backbone.Collection.extend({
model: HeroesModel,
url: 'http://example.com/heroes.json'
});
HeroesRouter = Backbone.Router.extend({
// I use two shows to graphic this example
routes: {
'': 'index',
':id': 'show'
},
initialize: function(options) {
this.collection = options.collection;
this.collection.fetch();
// this.collection.fetch({async:false}); this fixes my problem, but I heard it is a bad practice
},
index: function() {
},
show: function(id) {
console.log(this.collection.get(id).get('name'));
// Case #1: When Collection loads from a Variable
// id 1 returns: 'Batman'
// Case #2: When Collection fetchs from URL, id 1 returns:
// TypeError: this.collection.get(...) is undefined
}
});
// Case #1: collection loads JSON from a variable
var heroesCollection = new HeroesCollection(heroes);
// Case #2: collection loads JSON with fetch in router's initialize
// var heroesCollection = new HeroesCollection();
var heroesRouter = new HeroesRouter({collection: heroesCollection});
How about this? It's been awhile, but this seems like a better approach to what you are trying to achieve. The basic concept is that once you navigate to your show route, it will execute show. This method will create a new, empty collection, and then fetch the data for it. Along with that, we pass in a success method (as François illustrated) which will execute when the request is finished with the JSON (which creates a collection of Heros).
I believe the reason you were running into the issue with the remote data is that you were trying to access this.collection before it was populated with data from the request.
You have to remember the request is asynchronous, which mean code execution continues while the request is processing.
HeroesCollection = Backbone.Collection.extend({
model: HeroesModel,
url: 'http://example.com/heroes.json'
});
HeroesRouter = Backbone.Router.extend({
routes: {
'': 'index',
':id': 'show'
},
index: function() {
},
show: function(id) {
this.herosCollection = new HerosCollection();
this.herosCollection.fetch({
success: function(collection, response, options) {
console.log(this.get(id).get('name'));
}
});
}
});
you need to trigger the router 'show' function when the collection has ended to load.
this.collection.fetch({async:false}); fixes your problem because the whole javascript code is waiting (async:false) the ajax call to be ended before going further.
The other and best solution is to wait that your collection is fetched before you try to use the results.
Basically:
MyCollection.fetch({
success: function(model, reponse) {
// do wtv you want with the result here or trigger router show method...
}
});

AngularJS problems with $resource and web servers

I have been testing this code for 2 months, it is the first exercise in my tutorial to learn AngularJS.
The challenge is to count all .json files in a folder and increment it with 1 so that when I save another json file it will always have a higher ID then the previous one. I am having lots of trouble with web servers, first of all NodeJS does not seem to allow JSON posts in its standard configuration. So I have found a modified web-server.js from stockoverflow from a different question:
$resource.save is not functioning
https://github.com/glepretre/angular-seed/commit/9108d8e4bf6f70a5145b836ebeae0db3f29593d7#diff-d169b27b604606d4223bd5d85cad7da1 I have also tried the web-server.js that came with the tutorial:
http://pastebin.com/Ckfh4jvD that seemed to work better. WAMP also did not work I could not get Apache to allow JSON posts.
Problem is the web-server posts the json or sees the json as an object not as an array, even though I have used "isArray: true" and I use .query() instead of .get(). And I have tried many other things like transformResponse: []. I need the array to get .length to work! Also sometimes it GETS an array and POSTS an object which it later reads as object again it is getting really weird.
The code works sometimes as posted or sometimes I need to change :id to :id.json, usually this means the server is retrieving it as an object again which is not what I wan but this differs between the 2 nodeJS servers.
.factory('eventData', ['$resource', '$q', function ($resource, $q) {
var resource = $resource('/app/data/event/:id', {id: '#id'}, {"getAll": {method: "GET", isArray: true}});
var number = resource.query();
console.log(number);
return {
getEvent: function () {
var deferred = $q.defer();
resource.get({id: 1},
function (event) {
deferred.resolve(event);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
},
save: function (event) {
var deferred = $q.defer();
event.id = number.length;
resource.save(event,
function (response) {
deferred.resolve(response);
},
function (response) {
deferred.reject(response);
}
);
return deferred.promise;
}
};
}]);
EDIT: This seems to work better however I need to figure out how to put an .then() into this service?
.factory('eventData', ['$resource', '$q', function ($resource, $q) {
var resource = $resource('/app/data/event/:id.json',
{id: '#id'}, {method: "getTask", q: '*' },
{'query': { method: 'get'}});
var number = resource.query();

IBM Worklight JSONStore - Add and get data

I am using worlight JSONstore. I am new to it. I tried searching that read all docs but didn't get much idea.
I have one login page from that I get some json data I want to store that data using jsonstore. and get that afterwards.
I made jsonstore adapter.
Json-Store-Impl.js
function getJsonStores(custData) {
var data = custData;
return data;
//custdata is json
}
function addJsonStore(param1) {
var input = {
method : 'put',
returnedContentType : 'json',
path : 'userInputRequired'
};
return WL.Server.invokeHttp(input);
}
function updateJsonStore(param1) {
var input = {
method : 'post',
returnedContentType : 'json',
path : 'userInputRequired'
};
return WL.Server.invokeHttp(input);
}
function deleteJsonStore(param1) {
var input = {
method : 'delete',
returnedContentType : 'json',
path : 'userInputRequired'
};
return WL.Server.invokeHttp(input);
}
after that I Create a local JSON store.
famlCollection.js
;(function () {
WL.JSONStore.init({
faml : {
searchFields: {"response.mci.txnid":"string","response.mci.scrnseqnbr":"string","response.loginUser":"string","request.fldWebServerId":"string","response.fldRsaImageHeight":"string","request.fldRequestId":"string","request.fldTxnId":"string","response.fldDeviceTokenFSO":"string","response.fldRsaCollectionRequired":"string","response.datlastsuccesslogin":"string","response.fldRsaUserPhrase":"string","response.fldRsaAuthTxnId":"string","response.rc.returncode":"string","response.datcurrentlogin":"string","response.mci.deviceid":"string","response.customername":"string","request.fldDeviceId":"string","response.fldRsaUserStatus":"string","request.fldScrnSeqNbr":"string","response.fldRsaImageWidth":"string","request.fldLangId":"string","response.fldTptCustomer":"string","response.encflag":"string","response.rc.errorcode":"string","response.fldRsaImagePath":"string","response.mci.appid":"string","response.mci.requestid":"string","response.rc.errormessage":"string","response.mci.appserverid":"string","response.fldRsaCollectionType":"string","request.fldAppId":"string","response.fldRsaImageId":"string","request.fldLoginUserId":"string","response.mci.sessionid":"string","response.mci.langid":"string","response.mci.remoteaddress":"string","request.fldAppServerId":"string","response.mci.webserverid":"string","response.fldRsaImageText":"string","response.fldRsaEnrollRequired":"string","response.fldRsaActivityFlag":"string"},
adapter : {
name: 'JsonStore',
replace: 'updateJsonStore',
remove: 'deleteJsonStore',
add: 'addJsonStore',
load: {
procedure: 'getJsonStores',
params: [],
key: 'faml'
},
accept: function (data) {
return (data.status === 200);
}
}
}
}, {
password : 'PleaseChangeThisPassword'
})
.then(function () {
WL.Logger.debug(['Take a look at the JSONStore documentation and getting started module for more details and code samples.',
'At this point there is no data inside your collection ("faml"), but JSONStore is ready to be used.',
'You can use WL.JSONStore.get("faml").load() to load data from the adapter.',
'These are some common JSONStore methods: load, add, replace, remove, count, push, find, findById, findAll.',
'Most operations are asynchronous, wait until the last operation finished before calling the next one.',
'JSONStore is currently supported for production only in Android and iOS environments.',
'Search Fields are not dynamic, call WL.JSONStore.destroy() and then initialize the collection with the new fields.'].join('\n'));
})
.fail(function (errObj) {
WL.Logger.ctx({pretty: true}).debug(errObj);
});
}());
When I clicked on login button I call getJsonStores like this -
getJsonStores = function(){
custData = responseData();
var invocationData = {
adapter : "JsonStore",
procedure : "getJsonStores",
parameters : [custData],
compressResponse : true
};
//WL.Logger.debug('invoke msg '+invocationData, '');
WL.Client.invokeProcedure(invocationData, {
onSuccess : sucess,
onFailure : AdapterFail,
timeout: timeout
});
};
I followed these steps
Is this right way? and how can I check jsonstore working locally or not? and how can I store my jsondata in JSONStore? Where should I initialize the wlCommonInit function in project?
plz Help me out.
Open main.js and find the wlCommonInit function, add the JSONStore init code.
WL.JSONStore.init(...)
You already have an adapter that returns the data you want to add to JSONStore, call it any time after init has finished.
WL.Client.invokeProcedure(...)
Inside the onSuccess callback, a function that gets executed when you successfully get data from the adapter, start using the JSONStore API. One high level way to write the code would be, if the collection is empty (the count API returns 0), then add all documents to the collection.
WL.JSONStore.get(collectionName).count()
.then(function (countResult) {
if(countResult === 0) {
//collection is empty, add data
WL.JSONStore.get(collectionName).add([{name: 'carlos'}, {name: 'mike'}])
.then(function () {
//data stored succesfully
});
}
});
Instead of adding [{name: 'carlos'}, {name: 'mike'}] you probably want to add the data returned from the adapter.
Later in your application, you can use the find API to get data back:
WL.JSONStore.get(collectionName).findAll()
.then(function (findResults) {
//...
});
There is also a find API that takes queries (e.g. {name: 'carlos'}), look at the getting started module here and the documentation here.
It's worth mentioning that the JSONStore API is asynchronous, you must wait for the callbacks in order to perform the next operation.