Knockout combining multiple json data into single vm - javascript

I want to combine multiple json data into a single vm. I read that you can map from js into the model multiple times and it should be merging but on my case, it's not. It's replacing the data.
function Item(ID, Name, Description) {
this.ID = ko.observable(ID);
this.Name = ko.observable(Name);
this.Description = ko.observable(Description);
}
var MasterViewModel = {
model: ko.observableArray([])
};
$.getJSON(url, function (response) {
ko.mapping.fromJS(response["TM1.Cube"], Item, MasterViewModel.model);
ko.mapping.fromJS(response["TM1.Dimension"], Item, MasterViewModel.model);
})
ko.applyBindings(MasterViewModel);
And here is my json data
{
"LogicalName": "TM1.Model",
"ID": "12345",
"Name: "Sample",
"TM1.Cube": [
{
"LogicalName": "TM1.Cube",
"ID": "111111",
"Name": Assets"
},
{
"LogicalName": "TM1.Cube",
"ID": "111112",
"Name": Finance"
}
],
"TM1.Dimension": [
{
"LogicalName": "TM1.Dimension",
"ID": "222221",
"Name": Assets"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222222",
"Name": Finance"
}
]
}
and the outcome I expected is like this
{
"LogicalName": "TM1.Cube",
"ID": "111111",
"Name": Assets"
},
{
"LogicalName": "TM1.Cube",
"ID": "111112",
"Name": Finance"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222221",
"Name": KPI"
},
{
"LogicalName": "TM1.Dimension",
"ID": "222222",
"Name": Default"
}
I have added a jsFiddle http://jsfiddle.net/e1ppj3qc/1/

The mapping plugin can take an existing model but I don't believe it will merge data.
For example you could map twice like so:
{one: "yo"}
and
{two: "dawg"}
into the same model and you would now have two observables, one() and two()
But if you was to do this (which you are):
{one: ["yo"]}
and
{one: ["dawg"]}
it will always overwrite the matched properties.
You could instead do the mapping and then simply push into the array that you want to add to like so:
function pushCubs(dataToPush) {
ko.utils.arrayPushAll(MasterViewModel.modelcub, dataToPush());
}
pushCubs(ko.mapping.fromJS(data));
pushCubs(ko.mapping.fromJS(data2));
http://jsfiddle.net/e1ppj3qc/2/

Related

Use data from Quandl API to show in Appsmith table widget

I am building a web-app and want to connect data from Quandl through its JSON API.
However, the JSON I get from quandl has the column names separate from the data itself, check below:
{
"datatable": {
"data": [
[
"AAPL",
"MRY",
"2020-12-31",
"2020-09-26",
"2020-09-26",
"2021-07-28",
-406000000,
323888000000,
325562500000
]
],
]
],
"columns": [
{
"name": "ticker",
"type": "String"
},
{
"name": "dimension",
"type": "String"
},
{
"name": "calendardate",
"type": "Date"
},
{
"name": "datekey",
"type": "Date"
},
{
"name": "reportperiod",
"type": "Date"
},
{
"name": "lastupdated",
"type": "Date"
},
{
"name": "accoci",
"type": "Integer"
},
{
"name": "assets",
"type": "Integer"
},
{
"name": "assetsavg",
"type": "Integer"
}
]
},
"meta": {
"next_cursor_id": null
}
}
When I use this data in Appsmith, it can not infer the column names. Is there a simple javascript code to combine the column names with the data? Thank you!
This is possible with a simple JS snippet, Now my code written is not that great but will work in this case (Can be optimised)
{{
function() {
let tableData = [];
_.map(_d.datatable.data, (v, i) => {
let set = {}
_.map(v, (x, k) => {
var obj = {[_d.datatable.columns[k].name]: x}
set = {...set, ...obj}
})
tableData.push(set)
})
}()
}}
In the above snippet _d is the data which you receive, We map the array value index with the given column index and create a new object out of it, Also since this is a multiline JS code, In Appsmith we need to write this inside an IIFE like above.

Reverse Traverse a hierarchy

I have a hierarchy of objects that contain the parent ID on them. I am adding the parentId to the child object as I parse the json object like this.
public static fromJson(json: any): Ancestry | Ancestry[] {
if (Array.isArray(json)) {
return json.map(Ancestry.fromJson) as Ancestry[];
}
const result = new Ancestry();
const { parents } = json;
parents.forEach(parent => {
parent.parentId = json.id;
});
json.parents = Parent.fromJson(parents);
Object.assign(result, json);
return result;
}
Any thoughts on how to pull out the ancestors if I have a grandchild.id?
The data is on mockaroo curl (Ancestries.json)
As an example, with the following json and a grandchild.id = 5, I would create and array with the follow IDs
['5', '0723', '133', '1']
[{
"id": "1",
"name": "Deer, spotted",
"parents": [
{
"id": "133",
"name": "Jaime Coldrick",
"children": [
{
"id": "0723",
"name": "Ardys Kurten",
"grandchildren": [
{
"id": "384",
"name": "Madelle Bauman"
},
{
"id": "0576",
"name": "Pincas Maas"
},
{
"id": "5",
"name": "Corrie Beacock"
}
]
},
There is perhaps very many ways to solve this, but in my opinion the easiest way is to simply do a search in the data structure and store the IDs in inverse order of when you find them. This way the output is what you are after.
You could also just reverse the ordering of a different approach.
I would like to note that the json-structure is a bit weird. I would have expected it to simply have nested children arrays, and not have them renamed parent, children, and grandchildren.
let data = [{
"id": "1",
"name": "Deer, spotted",
"parents": [
{
"id": "133",
"name": "Jaime Coldrick",
"children": [
{
"id": "0723",
"name": "Ardys Kurten",
"grandchildren": [
{
"id": "384",
"name": "Madelle Bauman"
},
{
"id": "0576",
"name": "Pincas Maas"
},
{
"id": "5",
"name": "Corrie Beacock"
}
]
}]
}]
}]
const expectedResults = ['5', '0723', '133', '1']
function traverseInverseResults(inputId, childArray) {
if(!childArray){ return }
for (const parent of childArray) {
if(parent.id === inputId){
return [parent.id]
} else {
let res = traverseInverseResults(inputId, parent.parents || parent.children || parent.grandchildren) // This part is a bit hacky, simply to accommodate the strange JSON structure.
if(res) {
res.push(parent.id)
return res
}
}
}
return
}
let result = traverseInverseResults('5', data)
console.log('results', result)
console.log('Got expected results?', expectedResults.length === result.length && expectedResults.every(function(value, index) { return value === result[index]}))

node.js merging two json documents using request

I'm having trouble getting two JSON APIs on a website to merge into a single array rather than two.
My two JSON strings look like this:
{
"users": [
{
"name": "test1",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test2",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test3",
"uniqueid": "randomlygeneratedUUID"
}
}
{
"users": [
{
"name": "test4",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test5",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test6",
"uniqueid": "randomlygeneratedUUID"
}
}
and using something like Request, I grab the two URLs (the code looks like this):
var RequestMultiple = function (urls, callback) {
'use strict';
var results = {}, t = urls.length, c = 0,
handler = function (error, response, body) {
var url = response.request.uri.href;
results[url] = { error: error, response: response, body: body };
if (++c === urls.length) { callback(results); }
};
while (t--) { request(urls[t], handler); }
};
var DoRequest = function() {
var urls = ["url1", "url2"];
RequestMultiple(urls, function(responses) {
for (url in responses) {
response = responses[url];
if (response.body){
var JsonBody1 = JSON.parse(response[urls[0]]);
var JsonBody2 = JSON.parse(response[urls[1]]);
var MergeJsonBody = JsonBody1.concat(JsonBody2);
console.log(JSON.stringify(MergeJsonBody).toString());
} else {
console.log('Url', url, response.error);
}
}
});
});
console.log(DoRequest());
The issue I'm having is it doesn't merge, but when it does it looks like this:
{"users": [{ "name": "test1","uniqueid": "randomlygeneratedUUID"},{ "name": "test2","uniqueid": "randomlygeneratedUUID"},{ "name": "test3","uniqueid": "randomlygeneratedUUID"}} unidentified {"users": [{ "name": "test4","uniqueid": "randomlygeneratedUUID"},{ "name": "test5","uniqueid": "randomlygeneratedUUID"},{ "name": "test6","uniqueid": "randomlygeneratedUUID"}}
And it returns an error about the string unidentified.
When I don't get that error, it only shows the second JSON body.
What am I doing wrong? And is there a module or a best in practice way to do this?
EDIT:
Okay I took the solution provided, and I still hit a wall. To counter the issues I basically just had two unique requests that add to a local array variable, then once the command was triggered, create the array, then erase all the items from the array and start all over again. Thanks for all the help!
First of all both of your JSONs are missing closing square brackets. I guess its typo but below is the correct JSON.
{
"users": [
{
"name": "test4",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test5",
"uniqueid": "randomlygeneratedUUID"
},
{
"name": "test6",
"uniqueid": "randomlygeneratedUUID"
}
]
}
Now change below line of code
JsonBody1.concat(JsonBody2);
to
JsonBody1.users.concat(JsonBody2.users);
This will should give you expected results. You are doing concat on the actual objects instead of arrays.

How do I loop through this Json object (angularJS)?

I'm trying to loop through "tabs" in the Json object using AngularJS? How can I do it?
var model = {
"$id": "1",
"tabs": [{
"$id": "2",
"id": 2,
"name": "Output",
"layoutId": 1,
"order": 1,
"dashboardId": 1
}, {
"$id": "15",
"id": 3,
"name": "Yield",
"layoutId": 1,
"order": 2,
"dashboardId": 1
}, {
"$id": "24",
"id": 4,
"name": "Trend",
"layoutId": 1,
"order": 3,
"dashboardId": 1
}],
"id": 1,
"name": "Test",
"title": "Test",
"description": "Test Dashboard",
"createDate": "2015-06-08T00:00:00+01:00",
"ownerId": 1,
"enabled": true
};
When I try this, I get "undefined" in the console.
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
not sure what I'm doing wrong?
EDIT:
The data is coming from ASP.Net controller:
$http.get("/Dashboards/GetDashboardData").success(function (data) {
model = data;
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
}).error(function (data) {
console.log("error");
});
I expect that the model is not ready at the time you loop though it. Run the following code with your inspector open - the code you have is correct, but in your case fails because model isn't ready when you run the loop.
If you're loading data asyncronously you'll want to wait until the data is returned, either using a promise or a callback, and the loop through it.
var model = {
"tabs": [{
"name": "Output",
}, {
"name": "Yield",
}, {
"name": "Trend",
}],
};
angular.forEach(model.tabs, function (tab) {
console.log(tab.name);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Ok I found the answer. It looks like my controller returns Json object as a string, so I have to switch it to object before I can use it as an object.
I have add this line before using model in the loop:
model = JSON.parse(data);
The whole solution with promise (not sure if I need it now):
DataService.getDashboardData().then(function (data) {
model = JSON.parse(data);
angular.forEach(model.tabs, function (tab) {
console.log(tab);
});
});
app.service("DataService", ["$http", "$q", function ($http, $q) {
return {
getDashboardData: function () {
var dfd = $q.defer();
$http.get('/Dashboards/GetDashboardData').success(function (result) {
dfd.resolve(result);
});
return dfd.promise;
}
};
}]);

Accessing second array in a JSON decode using Jquery

I need to access the second array from a JSON decoded string, but I am having no luck.
The entire JSON string is displayed in var RAW00, and then split into var RAW01 & var RAW02.
All 3 of these are for testing - RAW00 is identical to msg
When they are split - I can access either, depending on what variable I start of with, but when I use RAW00 I cannot access the tutor section.
I will provide more detail if required, but my question is:
How do I see and access the tutor array in the second $.each (nested) block??]
Thanks :-)
success: function(msg)
{
var test = "";
var raw00 = {
"allData": [
{
"class2": [
{
"tid": "1",
"name": "Monday 2"
},
{
"tid": "1",
"name": "Monday Test"
}
]
},
{
"tutor": [
{
"fname": "Jeffrey",
"lname": "Kranenburg"
},
{
"fname": "Jeffrey",
"lname": "Kranenburg"
}
]
}
]
};
var raw01 = {
"allData": [
{
"class2": [
{
"tid": "1",
"name": "Monday 2"
},
{
"tid": "1",
"name": "Monday Test"
}
]
}
]
};
var raw02 = {
"allData": [
{
"tutor": [
{
"fname": "Jeffrey",
"lname": "Kranenburg"
},
{
"fname": "Jeffrey",
"lname": "Kranenburg"
}
]
}
]
};
$.each(raw00.allData, function(index, entry)
{
$.each(entry.class2, function (index, data)
{
console.log(this.name);
test += '<tr><td>'+this.name+'</td>';
});
$.each(entry.tutor, function (index, data)
{
console.log(this.fname);
test += '<td>'+this.name+'</td></tr>';
});
$('#all-courses-table-content').html( test );
});
You need to check whether the current element of the array is an object with class2 property or tutor property.
$.each(raw00.allData, function(index, entry) {
if (entry.hasOwnProperty('class2')) {
$.each(entry.class2, function (index, data)
{
console.log(this.name);
test += '<tr><td>'+this.name+'</td>';
});
}
if (entry.hasOwnProperty('tutor')) {
$.each(entry.tutor, function (index, data)
{
console.log(this.fname);
test += '<td>'+this.fname+'</td></tr>';
});
}
$('#all-courses-table-content').html( test );
});
Things would probably be simpler if you redesigned the data structure. It generally doesn't make sense to have an array of objects when each object just has a single key and it's different for each. I suggest you replace the allData array with a single object, like this:
var raw00 = {
"allData": {
"class2": [
{
"tid": "1",
"name": "Monday 2"
},
{
"tid": "1",
"name": "Monday Test"
}
],
"tutor": [
{
"fname": "Jeffrey",
"lname": "Kranenburg"
},
{
"fname": "Jeffrey",
"lname": "Kranenburg"
}
]
}
};

Categories

Resources