I'm using jQuery.dynatree plugin, how to load JSON formatted data using AJAX?
I do all as said in documentation:
<script>
$(function() {
$( "#Tree" ).dynatree({
title:"Thetree",
imagePath:'/jquery/css/',
selectMode:1,
initAjax:{
url:"http://127.0.0.1:2013/jsfolderstree"
}
});
});
</script>
The JS scripts is correctly connected to the HTML page, witout errors.
The requested URL by AJAX returns valid JSON:
[{
"key": "0x55638DB3",
"children": [
{
"key": "0x5D43E57C",
"children": [
{
"key": "0x70A4C1CE",
"children": [
{
"key": "0x799E9590",
"children": [],
"expand": true,
"tooltip": "This is group 5",
"isFolder": true,
"title": "Group 5"
},{
"key": "0x78C952A8",
"children": [],
"expand": true,
"tooltip": "This is group 6",
"isFolder": true,
"title": "Group 6"
}],
"expand": true,
"tooltip": "This is group 3",
"isFolder": true,
"title": "Group 3"
}],
"expand": true,
"tooltip": "This is group 1",
"isFolder": true,
"title": "Group 1"
},{
"key": "0x45B98999",
"children": [
{
"key": "0x6C829354",
"children": [],
"expand": true,
"tooltip": "This is group 4",
"isFolder": true,
"title": "Group 4"
}],
"expand": true,
"tooltip": "This is group 2",
"isFolder": true,
"title": "Group 2"
},{
"key": "0x47BE4570",
"children": [],
"expand": true,
"tooltip": "This is group 7",
"isFolder": true,
"title": "Group 7"
}],
"expand": true,
"tooltip": "Main level of tree",
"isFolder": true,
"title": "Root"
}]
But in result I have message "Loading Error" amd nothing more...
Where is my mistake?
I need load some JSON tree to the web-page, the tree must have methods to get selected node, and visual selection by mouse, that is that I need. Maybe need to use more simple plugins?
Thanks!
If you using jQuery ajax to load a JSON data,jQuery will resolve JSON data by JSON.parse method.
So don't put your JSON data in [], it will call parse error in jQuery ajax method.
{
"key": "0x55638DB3",
"children": [{...}]
....
}
Related
I have an object parsed from JSON output.
I have to use only pure JS without any 3rd part libs. Can somebody suggest a working solution to filter a specific nested object by one of its key's value. In this sample I have a few "Fields" objects which contains also nested objects.
So is there a way to filter the whole nested object inside Fields using VName value as a filter criteria? For example use "VName": "oc_data" to filter the whole object inside Fields oc_data belongs to
[{
"Id": "0050560107dd",
"Name": "Demo Range",
"AllMup": false,
"Lines": [{
"Id": "0050560107dd",
"AllMup": false,
"Fields": [{
"Id": "0050560107dd",
"Name": "Some value here",
"VName": "oc_data",
"IsRequired": false,
"Format": {
"Type": "Dictionary",
"Dictionary": {
"Name": "Main stuff",
"SysName": "da3a45de77d1",
"ValuesUrl": "https://mysityurl.com",
"Id": "0050560107dd",
},
"CalForm": []
}
}]
},
{
"Id": "0050560107dd",
"AllMup": false,
"Fields": [{
"Id": "0050560107dd",
"Name": "Some value again",
"VName": "task_stat",
"IsRequired": false,
"Format": {
"Type": "Dictionary",
"Dictionary": {
"Name": "Task stuff",
"SysName": "Tasks.TaskState",
"ValuesUrl": "https://mysecondurl.com",
"Id": "ac1f6b17f99d",
},
"CalForm": []
}
}]
}
]
},
{
"Id": "0050560107dd",
"Name": "Demo Range",
"AllMup": false,
"Lines": [{
"Id": "0050560107dd",
"AllMup": false,
"Fields": [{
"Id": "0050560107dd",
"Name": "Category",
"IsRequired": false,
"Format": {
"Type": "Dictionary",
"Dictionary": {
"Name": "Some category",
"SysName": "LitigationCategory",
"ValuesUrl": "https://myempty.com",
"Id": "902b343a9588",
},
"CalForm": []
}
}]
}]
}
]
I have an array of objects that looks something like this:
const roles = [
{
"id": "833ffe3d-cc24-4157-966c-5f8ceb856f4e",
"hidden": false,
"modified": "2020-03-20T15:14:12.689Z",
"label": "Solution 2",
"shortname": "Solution 2",
"description": "Solution 2 description",
"className": "Solution",
"children": [
{
"id": "f1708329-eb9f-4042-bbe7-cdd1ff41b1b7",
"hidden": false,
"modified": "2020-03-20T15:14:12.293Z",
"label": "USER CUSTOM ROLE",
"displayName": "USER CUSTOM ROLE DISPLAY NAME",
"className": "Role"
}
]
},
{
"id": "1a36709f-4de2-4f93-bf8e-57811d36e9f3",
"hidden": false,
"modified": "2020-03-20T15:14:12.668Z",
"label": "Solution 1",
"shortname": "Solution 1",
"description": "Solution 1 description",
"className": "Solution",
"children": [
{
"id": "e824afbd-8b19-4363-b6fa-dd604f445cef",
"hidden": false,
"modified": "2020-03-20T15:14:12.271Z",
"label": "USER ROLE",
"displayName": "USER ROLE DISPLAY NAME",
"className": "Role"
},
{
"id": "8f2600d0-5328-4d41-8270-2eb10541860f",
"hidden": false,
"modified": "2020-03-20T15:14:12.095Z",
"label": "BASE LOGIN ROLE",
"displayName": "DISPLAY NAME - BASE LOGIN ROLE",
"className": "Role"
},
{
"id": "a14ce471-b792-4a5d-95ad-b9abb5dbe45c",
"hidden": false,
"modified": "2020-03-20T15:14:12.102Z",
"label": "ORGANIZATION GLOBAL ROLE",
"displayName": "DISPLAY NAME - GLOBAL ROLE",
"className": "Role"
},
{
"id": "d4a7d6ac-1663-48be-9fed-ce2a908f28f1",
"hidden": false,
"modified": "2020-03-20T15:14:12.130Z",
"label": "DEPARTMENT 1 ROLE",
"className": "Role"
}
]
}
];
Point of my concern is id, label and children of these objects. As you can see, some of the roles objects contain their own roles array. And I have another array of selected roles, which looks like this:
const selected = ["Solution 1", "USER ROLE", "DEPARTMENT 1 ROLE"];
What I want is to create flat array of IDs corresponding to the selected roles, e.g. for this
selected array it will be (order is not important):
const result = ["d4a7d6ac-1663-48be-9fed-ce2a908f28f1", "e824afbd-8b19-4363-b6fa-dd604f445cef", "1a36709f-4de2-4f93-bf8e-57811d36e9f3"];
So my algorithm in pseudocode is:
1. Check root level object.
2. If it's label is in selected array, push it's id to the result array.
3. If it has children prop, check all it's children for the same condition.
4. Repeat for all other objects.
I've been only able to come up with very smelly function on this own and it still doesn't solve problem of the nested roles. My function is:
function getIds(arr, names) {
let result = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < names.length; j++) {
if (arr[i].label == names[j]) {
result.push(arr[i].id);
}
if (arr[i].children) {
for (let k = 0; k < arr[i].children.length; k++) {
if (arr[i].children[k].label == names[j]) {
result.push(arr[i].children[k].id);
}
}
}
}
}
return result;
}
I know, there are much more cleaner and prettier solutions, I just can't come up with one. Can you help?
First I would flatten the array what you have with roles using .flatMap(). Then simply with .map() matching the labels with the array elements and returning the ids.
Try the following:
const selected = ["Solution 1", "USER ROLE", "DEPARTMENT 1 ROLE"];
const roles = [{ "id": "833ffe3d-cc24-4157-966c-5f8ceb856f4e", "hidden": false, "modified": "2020-03-20T15:14:12.689Z", "label": "Solution 2", "shortname": "Solution 2", "description": "Solution 2 description", "className": "Solution", "children": [{ "id": "f1708329-eb9f-4042-bbe7-cdd1ff41b1b7", "hidden": false, "modified": "2020-03-20T15:14:12.293Z", "label": "USER CUSTOM ROLE", "displayName": "USER CUSTOM ROLE DISPLAY NAME", "className": "Role" } ] }, { "id": "1a36709f-4de2-4f93-bf8e-57811d36e9f3", "hidden": false, "modified": "2020-03-20T15:14:12.668Z", "label": "Solution 1", "shortname": "Solution 1", "description": "Solution 1 description", "className": "Solution", "children": [{ "id": "e824afbd-8b19-4363-b6fa-dd604f445cef", "hidden": false, "modified": "2020-03-20T15:14:12.271Z", "label": "USER ROLE", "displayName": "USER ROLE DISPLAY NAME", "className": "Role" }, { "id": "8f2600d0-5328-4d41-8270-2eb10541860f", "hidden": false, "modified": "2020-03-20T15:14:12.095Z", "label": "BASE LOGIN ROLE", "displayName": "DISPLAY NAME - BASE LOGIN ROLE", "className": "Role" }, { "id": "a14ce471-b792-4a5d-95ad-b9abb5dbe45c", "hidden": false, "modified": "2020-03-20T15:14:12.102Z", "label": "ORGANIZATION GLOBAL ROLE", "displayName": "DISPLAY NAME - GLOBAL ROLE", "className": "Role" }, { "id": "d4a7d6ac-1663-48be-9fed-ce2a908f28f1", "hidden": false, "modified": "2020-03-20T15:14:12.130Z", "label": "DEPARTMENT 1 ROLE", "className": "Role" } ] } ];
const flat = roles.flatMap(e => e.children.concat(e));
const result = selected.map(e => flat.find(f => f.label === e).id);
console.log(selected);
console.log(result);
I hope this helps!
I have this JSON which I'm parsing using NodeJS and it needs to be restructured into the second JSON which I've added below.
In the first JSON, the rows object has two pages objects (any number of pages objects can be present) which contains all the same keys and values with the exception of values and display keys.
{
"pages": [
{
"label": "SomeLabel",
"name": "Some",
"sections": [
{
"type": "Repeat",
"label": "Label 1",
"name": "Name 1",
"rows": [
{
"pages": [
{
"label": "Label 1",
"name": "Name 1",
"sections": [
{
"type": "Flow",
"label": "Label 2",
"name": "Name 2",
"answers": [
{
"label": "Question Label",
"question": "Question",
"values": [
"Value A"
],
"valuesMetadata": [
{
"display": "Display A",
"row": {
"columns": []
}
}
]
}
]
}
]
}
]
},
{
"pages": [
{
"label": "Label 1",
"name": "Name 1",
"sections": [
{
"type": "Flow",
"label": "Label 2",
"name": "Name 2",
"answers": [
{
"label": "Question Label",
"question": "Question",
"values": [
"Value B"
],
"valuesMetadata": [
{
"display": "Display B",
"row": {
"columns": []
}
}
]
}
]
}
]
}
]
}
],
"footer": null
}
]
}
]
}
In the second JSON the rows object has a single pages object, inside of which the values and display keys have multiple values (the non-common values).
{
"pages": [
{
"label": "SomeLabel",
"name": "Some",
"sections": [
{
"type": "Repeat",
"label": "Label 1",
"name": "Name 1",
"rows": [
{
"pages": [
{
"label": "Label 1",
"name": "Name 1",
"sections": [
{
"type": "Flow",
"label": "Label 2",
"name": "Name 2",
"answers": [
{
"label": "Question Label",
"question": "Question",
"values": [
"Value A",
"Value B"
],
"valuesMetadata": [
{
"display": [
"Display A",
"Display B"
],
"row": {
"columns": []
}
}
]
}
]
}
]
}
]
}
],
"footer": null
}
]
}
]
}
So, I want to know the fast and easy steps to do this. Please let me know the process and methods to solve this.
Thanks
If I understand you correctly, you want to combine all pages in a single page that holds all information.
This can be achieved using the Array.reduce function. reduce takes an array and combines all elements to a single value using a function (provided by you) to combine the first two elements until only one is left (i.e. 1 * 2 => new1; new1 * 3 => new2 where * represents your function).
Your problem would look something like this:
rows[0].pages = rows[0].pages.reduce((currentElement, currentState) => {
if (!currentState) { // first iteration return first element but make sure display is an array
currentElement.sections[0].answers[0].valuesMetadata[0].display =
[currentElement.sections[0].answers[0].valuesMetadata[0].display];
return currentElement;
}
// add values of current element to arrays in current state
currentState.sections[0].answers[0].values
.concat(currentElement.sections[0].answers[0].values);
currentState.sections[0].answers[0].valuesMetadata[0].display
.concat(currentElement.sections[0].answers[0].valuesMetadata[0].display);
return currentState;
});
currentElement is the object of the array that is currently reduced, currentState is the intermediate result of the reduction.
PS:
The object looks like you are way too many arrays where you would not need them. The given code snippet works only for the first element in each array (hence the [0]s. If you really do have multiple values in each array you would have to iterate over all of those accordingly.
I looking for best solution how to implement #observable on deep json object structure (for example a tree) data tree could be go really deep. and each node has many properties, but I need to observe only one property in tree node. Simply if I do
#observable questionnaire = {}
it works, but i think that is waist. I need observe only 'selected' property.
Here is json structure. Please correct me if i'm wrong here is questionnaire object simplified.
[
{
"id": "1",
"title": "level 1",
"description": "text",
"type": "Question",
"selected": false,
"childNodes": [
{
"title": "level 2",
"description": "text",
"type": "Question",
"selected": false,
"childNodes": [
{
"title": "level 3",
"description": null,
"type": "Question",
"selected": false,
"childNodes": [
{
"title": "level 4 1",
"childNodes": [],
"description": null,
"type": "Checkbox",
"selected": false
},
{
"title": "level 4 2",
"childNodes": [],
"description": null,
"type": "Checkbox",
"selected": false
},
{
"title": "level 4 3",
"childNodes": [],
"description": null,
"type": "Checkbox",
"selected": false
},
...
]
}, ...
One way is to have a Node class implemented as follows:
class Node {
#observable selected = false;
#observable childNodes = asFlat([]);
constructor(data) {
// Recursively create `Node` objects for all children.
data.childNodes = data.childNodes.map(child => new Node(child));
Object.assign(this, data);
}
}
Then you create a Node object from your top-level json object: new Node(json).
This solution will only observe selected and childNodes. It's not ideal because you need to wrap your json object in Node objects. But I can't think of any other way to do it.
I asked this question here:
Working With Dynamic Multidimensional key-value pairs in JSON
But it's become a bit more involved and I can't get where I'm going from that answer. If I have a data object that looks like this:
{
"email": "user#someco.com",
"firstname": "Bob",
"lastname": "Smith",
"company": "ACME",
"custom": {
"services": [
{
"name": "svc1",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc2",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc3",
"desc": "abcdefg",
"selected": "false",
"status": "None"
},
{
"name": "svc4",
"desc": "abcdefg",
"selected": "false",
"status": "None"
}
],
"fields": [
{
"name": "Products",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Product1",
"desc": "abcdef"
},
{
"name": "Product2",
"desc": "abcdef"
}
],
"services": [
"svc1",
"svc2",
"svc3"
]
},
{
"name": "Wines",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Wine 1",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
},
{
"name": "Fruits",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Fruit 1",
"desc": "abcdef"
},
{
"name": "Fruit 2",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
}
]
}
};
How can I convert that into an Angular menu? The menu would need to list all of the services, and then if the service has an associated item in "fields" that item should be listed underneath it. So for instance "svc1" and its description should be listed on a line (got that working) but then "Product1" and "Product2" with their descriptions should appear on the next two lines because you can see that "svc1" is listed in the "services" field for "Products." Similarly, "svc4" should appear on a line, and then "Wines" and its description on the next line because "svc4" appears in the "services" field of "Wines."
I think the best way is to unpack and re-pack this JSON object in sequential order in the Angular controller and then push this data out to the Angular view but there might be a solution using only the logic available from the view. I've tried a bunch of nested fors and ifs along these lines (very much not working):
var i, j;
var listArray = [];
for (i = 0; i < $scope.svcs.length; i++) {
var littleArray = [$scope.svcs[i].status, $scope.svcs[i].name, $scope.svcs.desc];
listArray.push[littleArray1];
for (j=0; j < $scope.jFA.length; j++) {
if ($scope.jFA[j] == $scope.svcs[i].name) {
if ($scope.jFA[j] == $scope.svcs[i].fields)
littleArray = [$scope.jFA[j].fields] //...etc
}
}
...but that logic just keeps getting more and more dense and isn't working no matter now I try to use it. I liked the simplicity in the answer to the other question but have not had success in replicating it.
So if someone can help me figure out how to get the data into the right sequence using JS I can handle the Angular part. Or if you're an Angular whiz and have an answer along those lines, even better.
So it was a little hard understanding your question, but I gave it my best shot. Does this fiddle show what you are trying to achieve? http://jsfiddle.net/arknr6qz/1/
JS:
var app = angular.module('TestApp',[]);
app.controller('TestController', function($scope)
{
$scope.checkService = function(service, fieldServices)
{
if (fieldServices.indexOf(service) != -1) return true;
return false;
};
$scope.data = {
"email": "user#someco.com",
"firstname": "Bob",
"lastname": "Smith",
"company": "ACME",
"custom": {
"services": [
{
"name": "svc1",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc2",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc3",
"desc": "abcdefg",
"selected": "false",
"status": "None"
},
{
"name": "svc4",
"desc": "abcdefg",
"selected": "false",
"status": "None"
}
],
"fields": [
{
"name": "Products",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Product1",
"desc": "abcdef"
},
{
"name": "Product2",
"desc": "abcdef"
}
],
"services": [
"svc1",
"svc2",
"svc3"
]
},
{
"name": "Wines",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Wine 1",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
},
{
"name": "Fruits",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Fruit 1",
"desc": "abcdef"
},
{
"name": "Fruit 2",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
}
]
}
};
});
HTML:
<div ng-app="TestApp">
<div ng-controller="TestController">
<div ng-repeat="service in data.custom.services">
{{ service.name }}
<div class="indent" ng-repeat="fields in data.custom.fields">
<span ng-if="checkService(service.name, fields.services)">
{{fields.services.values}}
<span ng-repeat="value in fields.values">
{{value.name}} - {{value.desc}}<br>
</span>
</span>
</div>
</div>
</div>
</div>
and finally css:
.indent {
margin-left:10px;
}