Mobx observable deep object - javascript

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.

Related

Javascript object nested filtering

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": []
}
}]
}]
}
]

How to find props of nested objects in array JavaScript?

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!

Check for Parent Child node in JSON using angular JS

I am looking for JSON parsing reference, from where I can jump to question and check for Child question based on Yes section. I didn't find anything related to check for child node check in JSON. Angular is my base framework.
some use cases :
on load show Root question,
On selection show next questions which is child of root then go one
jump to number of questions from tree.
treeObj={
"Root_Element": {
"id": "myTree",
"dt": {
"choice": {
"id": '0',
"title": "Which color",
"description": "Choose color ?",
"choice": [
{
"id": 1,
"title": "Yellow",
"description": "Yellow ? ,
"choice": [
{
"id": 5,
"title": "Dark Yellow",
"description": "Dark Yellow ?
},
{
"id": 4,
"title": "Light Yellow",
"description": "Light Yellow ?
}
]
},
{
"id": 2,
"title": "Red",
"description": "Red ?"
},
{
"id": 3,
"title": "Green",
"description": "Green ?
}
]
}
}
}
}
If the number of levels in the JSON object is fixed and if it does not grow dynamically, you can use the ES6 destructuring to read the data from the nested JSON. Below is an example
var metadata = {
title: "Scratchpad",
translations: [
{
locale: "de",
localization_tags: [ ],
last_edit: "2014-04-14T08:43:37",
url: "/de/docs/Tools/Scratchpad",
title: "JavaScript-Umgebung"
}
],
url: "/en-US/docs/Tools/Scratchpad"
};
var { title: englishTitle, translations: [{ title: localeTitle }] } = metadata;
console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"

different tree view icons and enable/disable checkboxes in jstree

I need to change the tree view icons and enable/disable checkboxes
please view the code below :
function LoadJSTree() {
$.noConflict();
$(function () {
$('#demoTree').jstree({
'checkbox': {
'keep_selected_style': false,
'two_state': true
},
"types": {
"#": {
"max_children": 1,
"max_depth": 4,
"valid_children": ["root"]
},
"root": {
"icon": "/static/3.1.1/assets/images/tree_icon.png",
"valid_children": ["default"],
"check_node": false,
},
"default": {
"valid_children": ["default", "file"],
"check_node": true,
"uncheck_node": true
},
"disabled":{
"check_node": false,
"uncheck_node": false
},
"file": {
"icon": "glyphicon glyphicon-file",
"valid_children": [],
"check_node": true,
"uncheck_node": true
}
},
"plugins": ["types"],
'core': {
'data': [
{
"text": "Root node", "type": "root", "parent":"#", "children": [
{ "text": "Child node 1", "type": "default" },
{ "text": "Child node 2", "type": "default" },
{ "text": "Child node 3", "type": "default" },
{ "text": "Child node 4", "type": "default" },
{ "text": "Child node 5", "type": "default" },
{ "text": "Child node 6", "type": "default" },
{ "text": "Child node 7", "type": "default" },
{ "text": "Child node 8", "type": "default" }
]
}
],
},
'plugins': ["checkbox"]
});
It doesn't seem to work.
The tree is displayed using same folder icons for every node and check box always present for every node, shouldn't it come disabled for "root" node?
Could you please let me know what's wrong?
You have listed plugins twice in your config:
"plugins": ["types"],
...
'plugins': ["checkbox"]
Change that to a single entry:
"plugins": ["checkbox", "types"]
However keep in mind there is no option (in v.3, if that is the version you are using) to prevent actions based on the type of the node. But using the most recent jsTree commit you can disable checkboxes on a per node basis using the state property of the node (you can also disable the whole node) - if that is what you need have a look here:
jsTree disable some of the checkboxes

jQuery.Dunatree.How to load JSON tree using AJAX?

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": [{...}]
....
}

Categories

Resources