json.stringify slice array to word - angularjs

I use JSON.stringify(data); to return json
here is my code
var data;
programService.query({
id: $routeParams.id
}, function (result) {
data = { 'program': result };
data= JSON.stringify(data);
$scope.setPagingData(data,page,pageSize);
});
$scope.setPagingData = function(data, page, pageSize){
var pagedData = data.slice((page - 1) * pageSize, page * pageSize);
$scope.myData = pagedData;
$scope.totalServerItems = data.length;
if (!$scope.$$phase) {
$scope.$apply();
}
};
json data
{programId:1,
programName:project1,
programContent:content1,
programStartDate:2012-01-01,
templateId: "1"}
and the result will be p , r, o...
not a programId, 1, programName, project1.....
any ideas?

I'm not sure exactly what you are trying to do, but let me just point out some things in your code that could potentially point you in the right direction.
First, your JSON data (which I assume you mean as the result from your server:
{programId:1,
programName:project1,
programContent:content1,
programStartDate:2012-01-01,
templateId: "1"}
is pretty decently mal-formed. Double-quotes around both keys and values is proper JSON format (values that are numbers don't need quotes).
Second, assuming your JSON data is indeed how you want and expect it to be, in your callback function:
...
}, function (result) {
data = {
'program': result
};
...
});
...
result is a STRING (since JSON is simply a text-based serialization format and is always a string), meaning
data = {
'program': result
};
results in data looking like a JS object like this:
{ 'program' : '{programId:1, programName:project1, programContent:content1, programStartDate:2012-01-01, templateId: "1"}' }
Perhaps you meant to convert the JSON into a native JS object, in which case JSON.parse(result) is what you are looking for.
data = {
'program': JSON.parse(result)
};
data now looks like a JS object like this (assuming your JSON is well-formed, otherwise the parse function will break):
{
"program" : {
"programId" : 1,
"programName" : "project1",
"programContent" : "content1",
"programStartDate" : "2012-01-01",
"templateId" : "1"
}
}
Third, back to your callback function:
...
}, function (result) {
...
data= JSON.stringify(data);
$scope.setPagingData(data,page,pageSize);
});
...
data= JSON.stringify(data); converts the given data into a JSON string. If this is what you intend, then carry on!
Fourth, in your $scope.setPagingData function,
$scope.setPagingData = function(data, page, pageSize){
var pagedData = data.slice((page - 1) * pageSize, page * pageSize);
$scope.myData = pagedData;
$scope.totalServerItems = data.length;
if (!$scope.$$phase) {
$scope.$apply();
}
};
the .slice function and .length attribute are both part of the Array prototype. This means if your passed in data is a JS object, .slice will throw a "has no method slice" error and .length will return undefined.

Related

dealing with an array of objects with promises

I am trying to make a node express app where I fetch data from different url's making a call to node-fetch to pull the body of some pages and other information about certain url endpoints. I want to then render a html table to display this data through an array of information. I am having trouble with the call to render the information as all the functions are asynchronous making it difficult to make sure all the promise calls have been resolved before making my call to render the page. I have been looking into using bluebird and other promise calls of .finally() and .all() but they don't seem to work on my data as it is not an array of promise calls, but an array of objects. Each object was 4 promise calls to fetch data relating to a column of my table all in one row. Is there a function or specific way to render the page after all promises are resolved?
var express = require('express');
var fetch = require('node-fetch');
fetch.Promise = require('bluebird');
var router = express.Router();
const client = require('../platform-support-tools');
function makeArray() {
var registry = client.getDirectory();
var data_arr = [];
for (var i = 0; i < registry.length; i++) {
var firstUp = 0;
for (var j = 0; i < registry[i]; j++) {
if (registry[i][j]['status'] == 'UP') {
firstUp = j;
break;
}
}
var object = registry[i][firstUp];
data_arr.push({
'name': object['app'],
'status': object['status'],
'swagUrl': object['homePageUrl'] + 'swagger-ui.html',
'swag': getSwag(object),
'version': getVersion(object['statusPageUrl']),
'timestamp': getTimestamp(object['statusPageUrl']),
'description': getDescription(object['healthCheckUrl'])
});
}
return data_arr;
}
function getSwag(object_in) {
var homeUrl = object_in['homePageUrl'];
if (homeUrl[homeUrl.length - 1] != '/'){
homeUrl += '/';
}
var datum = fetch(homeUrl + 'swagger-ui.html')
.then(function (res) {
return res.ok;
}).catch(function (err) {
return 'none';
});
return datum;
}
function getVersion(url_in) {
var version = fetch(url_in)
.then(function(res) {
return res.json();
}).then(function(body) {
return body['version'];
}).catch(function (error) {
return 'none';
});
return version;
}
function getTimestamp(url_in) {
var timestamp = fetch(url_in)
.then(function(res) {
return res.json();
}).then(function(body) {
return body['timestamp'];
}).then(function (res) {
return body['version'];
}).catch(function (error) {
return 'none';
});
return timestamp;
}
function getDescription(url_in) {
var des = fetch(url_in)
.then(function(res) {
return res.json();
}).then(function(body) {
return body['description'];
}).catch(function (error) {
return 'none';
});
return des;
}
/* GET home page. */
router.get('/', function (req, res, next) {
var data_arr = makeArray();
Promise.all(data_arr)
.then(function (response) {
//sorting by app name alphabetically
response.sort(function (a, b) {
return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0);
});
res.render('registry', {title: 'Service Registry', arr: response})
}).catch(function (err) {
console.log('There was an error loading the page: '+err);
});
});
To wait on all those promises, you will have to put them into an array so you can use Promise.all() on them. You can do that like this:
let promises = [];
for (item of data_arr) {
promises.push(item.swag);
promises.push(item.version);
promises.push(item.timestamp);
promises.push(item.description);
}
Promise.all(promises).then(function(results) {
// all promises done here
})
If you want the values from all those promises, back into the object that's a bit more work.
let promises = [];
for (item of data_arr) {
promises.push(item.swag);
promises.push(item.version);
promises.push(item.timestamp);
promises.push(item.description);
}
Promise.all(promises).then(function(results) {
// replace promises with their resolved values
let index = 0;
for (let i = 0; i < results.length; i += 4) {
data_arr[index].swag = results[i];
data_arr[index].version = results[i + 1];
data_arr[index].timestamp = results[i + 2];
data_arr[index].description = results[i + 3];
++index;
});
return data_arr;
}).then(function(data_arr) {
// process results here in the array of objects
});
If you had to do this more often that just this once, you could remove the hard coding of property names and could iterate all the properties, collect the property names that contain promises and automatically process just those.
And, here's a more general version that takes an array of objects where some properties on the objects are promises. This implementation modifies the promise properties on the objects in place (it does not copy the array of the objects).
function promiseAllProps(arrayOfObjects) {
let datum = [];
let promises = [];
arrayOfObjects.forEach(function(obj, index) {
Object.keys(obj).forEach(function(prop) {
let val = obj[prop];
// if it smells like a promise, lets track it
if (val && val.then) {
promises.push(val);
// and keep track of where it came from
datum.push({obj: obj, prop: prop});
}
});
});
return Promise.all(promises).then(function(results) {
// now put all the results back in original arrayOfObjects in place of the promises
// so now instead of promises, the actaul values are there
results.forEach(function(val, index) {
// get the info for this index
let info = datum[index];
// use that info to know which object and which property this value belongs to
info.obj[info.prop] = val;
});
// make resolved value be our original (now modified) array of objects
return arrayOfObjects;
});
}
You would use this like this:
// data_arr is array of objects where some properties are promises
promiseAllProps(data_arr).then(function(r) {
// r is a modified data_arr where all promises in the
// array of objects were replaced with their resolved values
}).catch(function(err) {
// handle error
});
Using the Bluebird promise library, you can make use of both Promise.map() and Promise.props() and the above function would simply be this:
function promiseAllProps(arrayOfObjects) {
return Promise.map(arrayOfObjects, function(obj) {
return Promise.props(obj);
});
}
Promise.props() iterates an object to find all properties that have promises as values and uses Promise.all() to await all those promises and it returns a new object with all the original properties, but the promises replaced by the resolved values. Since we have an array of objects, we use Promise.map() to iterate and await the whole array of those.

How do you make JS think that a string is JSON?

how to convert in json object?
I also tried the following.
$scope.getEval = function (str) {
return eval(str);
};
try {
s = $scope.getEval("\nexports = { emptyFunction: function () { \n exit(); }, getUserName: function () { if (!variable.global_name) { exit(changeFlowAndStep('get_user_name', 0, {global_first_time_done: false}, true)); } else { exit({variable:{global_first_time_done: true}}); } }}")
for (var i in s) {
s[i] = s[i].toString();
}
$scope.s = s;
console.log($scope.s)
} catch (e) {
console.log(e);
}
If you have a javascript object, it is easy to generate a JSON string with JSON.stringify() and if you have a JSON string, it is easy to generate a javascript object with JSON.parse()
// going from JSON to JS object...
var json = '{"result":true,"count":1}',
obj = JSON.parse(json);
console.log(obj);
console.log(obj.count);
// from JS object to JSON string...
var str = JSON.stringify(obj);
console.log(str);
from:
Parse JSON in JavaScript?
Convert JS object to JSON string
Your use of eval works, as you can see when you call console.dir($scope.s);
It is possible to use json = JSON.stringify(obj); and obj = JSON.parse(json);. However it appears JSON.stringify ignores object fields with a function as a value. That is your string is not a useful json string.

Return value from angularjs factory

I try to set up this example https://github.com/AngularClass/angular-websocket#usage
Here is my code
App.factory('MyData', function($websocket, $q) {
var dataStream = $websocket('wss://url');
var collection = [];
dataStream.onMessage(function(message) {
var result = JSON.parse(message.data);
console.log(result);
collection = result;
});
var methods = {
collection: collection,
get: function() {
dataStream.send(JSON.stringify({
api: "volume",
date: "2017-02-01",
interval: 600
}));
}
};
return methods; });
In my controller I wrote:
$interval(function () {
console.log(MyData.collection);
}, 1000);
The problem is that I don't receive any values, however on message arrive I see console log, so websocket itself is obviously alive. If I change collection.push(result) (like in example) I receive constantly growing array. I need only the last value, however. Why collection = result is wrong ?
var collection = []; instantiates a new array and its reference is stored in the variable collection. Then, this reference is assigned to methods.collection and, hence, MyData.collection. However, with JSON.parse a new array is instantiated. collection = result; overwrites the original reference with the reference of the new array. But MyData.collection still holds the reference to original array.
So, there are two ways to encounter the problem:
Don't overwrite the reference to the original array. push is good, but before, you need to clear the array in order to only show the last value.
collection.splice(0, collection.length);
collection.push(result);
However, that would be an array in an array. You probably need to push the values individually (Array.concat will create a new array, too):
collection.splice(0, collection.length);
result.forEach(function(value) {
collection.push(value);
});
Assign the reference of the new array directly to methods.collection. In this case, no extra variable collection is needed.
App.factory('MyData', function($websocket, $q) {
var dataStream = $websocket('wss://url');
var methods = {
collection: [],
get: function() {
dataStream.send(JSON.stringify({
api: "volume",
date: "2017-02-01",
interval: 600
}));
}
};
dataStream.onMessage(function(message) {
var result = JSON.parse(message.data);
console.log(result);
methods.collection = result;
});
return methods;
});

Angular datatable and JSON structure issue

Here is my issue:
The datatable plug-in only accepts an array I believe but my API returns an object with an array. I am trying to figure out if I need to extract this info (how?) or if the plug-in has some methods that do that for me (there is one):
//the datatable plugin expects the following JSON structure
[
{
"ID":"a5f415a7-3d4f-11e5-b52f-b82a72d52c35",
"Record":1,
"HostName":"SRX552P"
}
]
//my PHP server returns the following JSON structure:
{
"status":"success",
"message":"data retrieved",
"data":[
{
"ID":"a5f415a7-3d4f-11e5-b52f-b82a72d52c35",
"Record":1,
"HostName":"SRX552P"
}
]
}
var allData = null;
//this is my angularjs service where I am grabbing all the 'data':
function getAllData() {
dataservice.get('table001').then(function(data){
allData = data;
});
return allData;
}
//it looks like my issue is exactly what this post describes:
http://stackoverflow.com/questions/27797435/accessing-json-data-in-angularjs-datatables-using-dtoptions
//but applying ".withDataProp('data.data')" didn't work for me:
...
this.standardOptions = DTOptionsBuilder
.fromFnPromise(getAllData())
.withDataProp('data.data')
//.fromSource('api/tables/datatables.standard.json') //static data works fine!
//Add Bootstrap compatibility
.withDOM("<'dt-toolbar'<'col-xs-12 col-sm-6'f><'col-sm-6 col-xs-12 hidden-xs'l>r>" +
"t" +
"<'dt-toolbar-footer'<'col-sm-6 col-xs-12 hidden-xs'i><'col-xs-12 col-sm-6'p>>")
.withBootstrap();
this.standardColumns = [
DTColumnBuilder.newColumn('ID'),
DTColumnBuilder.newColumn('Record'),
DTColumnBuilder.newColumn('HostName')
];
...
//this is the service
(function () {
'use strict';
angular.module('app.ipxtool').factory('dataservice', dataservice);
dataservice.$inject = ['$http', '$q'];
function dataservice($http, $q) {
var serviceBase = 'api/v1/';
var obj = {};
obj.get = function (q) {
return $http.get(serviceBase + q).then(success).catch(fail);
};
function success(results) {
if (results.data.status == "error") {
logger.error(results.data.message, '', 'Error'); //$response["data"] = null for errors;
}
if (results.data.status == "warning") {
logger.warning(results.data.message, '', 'Warning');
}
if (results.data.status == "success") {
logger.success(results.data.message, results.data.data, 'Success'); //$response["data"] = $rows;
}
return results.data;
}
function fail(e) {
return (e);
}
return obj;
};
})();
Using Fiddler I can see all the data being returned. Also I output the first array item as follows:
console.log("var allData: " + "[" + JSON.stringify(alldata.data[1]) + "]");
The solution to this issue was to add the following:
.fromFnPromise(function() {
return dataservice.get('table001');
})
Not sure why calling getAllData() didn't work. So finally I got this thing resolved. Thanks.
You can add [ and ] at the start and at the end of your output var in php page itself, so that it would return a proper JSON output. Since I also faced such issue earlier in Angular as it doesn't accept direct Object input, I used the above approach to convert it into full-fledged JSON.
Also add the below code at the top of your PHP page:
header('Content-Type: application/json');
So that, it'll return the content in JSON-formatted text.

passing data to a collection in backbone

So I am trying storing product types from a json file before trying to add them to a collection but am getting some strange results (as in I dont fully understand)
on my router page i setup a variable for cached products as well as product types
cachedProductTypes: null,
productType : {},
products : {},
getProductTypes:
function(callback)
{
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
var self = this;
$.getJSON('data/product.json',
function(data)
{
self.cachedProductTypes = data;
callback(data);
}
);
},
parseResponse : function(data) {
result = { prodTypes: [], products: [] };
var type;
var types = data.data.productTypeList;
var product;
var i = types.length;
while (type = types[--i]) {
result.prodTypes.push({
id: type.id,
name: type.name,
longName: type.longName
// etc.
});
while (product = type.productList.pop()) {
product.productTypeId = type.id,
result.products.push(product);
}
};
this.productType = result.prodTypes;
console.log( "dan");
this.products = result.products;
},
showProductTypes:function(){
var self = this;
this.getProductTypes(
function(data)
{
self.parseResponse(data);
var productTypesArray = self.productType;
var productList=new ProductsType(productTypesArray);
var productListView=new ProductListView({collection:productList});
productListView.bind('renderCompleted:ProductsType',self.changePage,self);
productListView.update();
}
);
}
when a user goes to the show product types page it runs the showProductsType function
So I am passing the products type array to my collection
on the collection page
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
$.each(this.productTypesArray, function(i,prodType){
tmpItem=new ProductType({id:prodType.id, name:prodType.name, longName:prodType.longName});
console.log(prodType.name);
self.add(tmpItem);
});
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
now this doesnt work as it this.productTypesArray is undefined if i console.log it.
(how am I supposed to get this?)
I would have thought I need to go through and add each new ProductType.
the strange bit - if I just have the code
var ProductsType=Backbone.Collection.extend({
model:ProductType,
fetch:function(){
var self=this;
var tmpItem;
//fetch the data using ajax
self.trigger("fetchCompleted:ProductsType");
}
});
return ProductsType;
it actually adds the products to the collection? I guess this means I can just pass an array to the collection and do not have to add each productType?
I guess this means I can just pass an array to the collection and do not have to add each productType?
Yes, you can pass an array to the collection's constructor, and it will create the models for you.
As far as your caching code, it looks like the problem is here:
if (this.cachedProductTypes !== null) {
return callback(cachedProductTypes);
}
The callback statement's argument is missing this - should be return callback(this.cachedProductTypes).

Resources