Access object child property without using parent - javascript

I am using the html2json which gives me back an object with child objects. Like the code below. I want to get the value of the key text. But it differs per case how many child objects there are and thus where the key text is situated.
The code I have tried but for this reason, did not work every time was this one:
json.child[0].child[0].child[0].child[0].text
And this is an example of an object:
node: 'root', child: [
{
node: 'element',
tag: 'div',
attr: { id: '1', class: 'foo' },
child: [
{
node: 'element',
tag: 'h2',
child: [
{ node: 'text', text: 'sample text with ' },
{ node: 'element', tag: 'code', child: [{ node: 'text', text: 'inline tag' }] }
]
}
]
} ]
Is there another way to access this element? I was thinking of searching for a key in the object because the key "text" only occurs once. But do not know how this would work.
All help is really appreciated!

You could create a recursive function that will return an array of all the values where the key matches.
const data = {"node":"root","child":[{"node":"element","tag":"div","attr":{"id":"1","class":"foo"},"child":[{"node":"element","tag":"h2","child":[{"node":"text","text":"sample text with "},{"node":"element","tag":"code","child":[{"node":"text","text":"inline tag"}]}]}]}]}
function findByKey(data, key) {
const result = [];
for (let i in data) {
if (i === key) result.push(data[i]);
if (typeof data[i] === 'object') {
result.push(...findByKey(data[i], key))
}
}
return result;
}
console.log(findByKey(data, 'text'))

Related

Can't push array item to array data property - Vue Js

I a getting data from the laravel using this response :
$unserialize = unserialize($import->field_names);
return response()->json( $unserialize, 200 ) ;
Now on the Vue JS I can console the response using this :
console.log(response);
and It's showing the data in array (Check the red arrow mark):
Now, I have a options empty array property like this:
options : []
I want to push object data to this array with a key value and text. This key's value will be that response data single item. So, To do this, I am using this:
response.data.forEach((item, index) => {
this.options.push({
value: item,
text: index
});
});
but If I console
console.log(this.options);
I can not see the array of object to this options propery. I can see this:
can you tell me why? I want this options should store the item like this:
options: [
{ value: null, text: 'Please select some item' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Default Selected Option' },
{ value: 'c', text: 'This is another option' },
{ value: 'd', text: 'This one is disabled', disabled: true },
]
Update:
Console.log(response);
I think that the problem could be in this keyword
you can modify your code in this way
this.options = [...this.options,
...response.data.map((item, index) =>
({
value: item,
text: index
})
)]

How to update a recurring nested object property using its previous value using Javascript?

I got an array with some elements and each element has some properties like name, id and children. Each element has children property and then sub children so on and so forth. This array is already there in our application. Now I want to update all of elements and sub elements of our array with a new property called "path". The "path" will be the key and its value will be the addition of its previous object's name. For example
let dataArray = [
{
name: 'Data',
id: 12,
path: 'Data',
children: [
{
name: 'Data Center',
id: 13,
path: 'Data/Data Center',
children: [
{
name: 'Data Management',
id: 13,
path: 'Data/Data Center/Data Managemet',
},
],
},
],
},
{
name: 'Machine',
id: 12,
path: 'Machine',
children: [
{
name: 'Machine Center',
id: 13,
path: 'Machine/Machine Center',
children: [
{
name: 'Machine Management',
id: 13,
path: 'Machine/Machine Center/Machine Managemet',
},
],
},
],
}
];
As you can see path property to all the elements. I want to make this happen programatically. For that, here is the piece of code I have written but I am not able to understand what need to need to be done to achieve. This piece of code adds path property to all the elements and sub elements but with name as path like above example. I want the addition of previous names which have been traversed.
addPathProperty(){
dataArray.forEach((element) =>{
element.path = element.name;
if(element.children.length > 0){
this.addPathProperty(element.children)
}
});
}
Here is the link Stackblitz. Any help will be appreciated. Thank you
I think this code should work:
const appendPath = (root = '') => (obj) => {
obj.path = root ? `${root}/${obj.name}` : obj.name
if (obj.children) {
obj.children.forEach(appendPath(obj.path))
}
}
dataArray.forEach(appendPath())
appendPath is a function that accepts a root, when this function is invoked, it will combine root and name and set this to object.path; After that, it will do the same for the object.children if they exists

Object hierarchy from XML document using JavaScript

Given an XML document such as this:
<Root>
<Child1>
<ChildOfChild1_1>
<FinalChild> </FinalChild>
</ChildOfChild1_1>
<ChildOfChild1_2> </ChildOfChild1_2>
</Child1>
<Child2>
<ChildOfChild2_1> </ChildOfChild2_1>
</Child2>
<Child3> </Child3>
</Root>
I would like to return a object which has only two parameters, name and children. It would look like:
{
name: "Root"
children: [
{
name: "Child1"
children: [
{
name: "ChildOfChild1_1"
children:[
{
name: "FinalChild"
children: null
}
]
},
{
name: "ChildOfChild1_2"
children: null
}
]
},
{
name: "Child2"
children: [
{
name: "ChildOfChild2_1"
children: null
}
]
},
{
name: "Child3"
children: null
},
]
}
I do not care about node attributes, only nodeName and if they have children. I wrote code to get the first level of children but cannot wrap my head around the recursive part to get as deep as necessary. Thanks.
Below is what I have so far:
//assuming block is the root node and the root will at least have 1 child
let root = {
name = '',
children = []
};
root.name = block.nodeName;
for(let i=0 ; i<block.children.length ; i++) {
root.children.push(getChildren(block.children[i]));
}
function getChildren(data) {
let child = {};
child.name = data.nodeName;
child.children = []; //stuck here
return child;
}
The task is much simpler than you think.
You want a function that returns a node name and the list of node children, each of them processed in the exact same way:
function toObject(node) {
return {
name: node.nodeName,
children: [...node.children].map(toObject)
};
}
That's it.
const xmlDoc = new DOMParser().parseFromString(`<Root>
<Child1>
<ChildOfChild1_1>
<FinalChild> </FinalChild>
</ChildOfChild1_1>
<ChildOfChild1_2> </ChildOfChild1_2>
</Child1>
<Child2>
<ChildOfChild2_1> </ChildOfChild2_1>
</Child2>
<Child3> </Child3>
</Root>
`, "application/xml");
function toObject(node) {
return {
name: node.nodeName,
children: [...node.children].map(toObject)
};
}
const tree = toObject(xmlDoc.documentElement);
console.log(tree);
If you really want null when there are no children (an empty array is much easier to handle down the line, trust me), I'm sure you can make the necessary change in toObject yourself.

Search Inside Dropdown with data in tree structure React JS

I have developed a custom component which renders dropdown with a tree like structure inside it and allows the user to search for values inside the dropdown. Somehow the search works only after two levels of the tree structure.
We would be able to search only on the inside of NextJS label. The previous levels do not render results.
My function looks like this:
const searchFunction = (menu: treeData[], searchText: string) => {
debugger; //eslint-disable-line no-debugger
for (let i = 0; i < menu.length; i++) {
if (menu[i].name.includes(searchText)) {
setFound(true);
return menu[i].name;
} else if (!menu[i].name.includes(searchText)) {
if (menu[i].children !== undefined) {
return searchFunction(menu[i].children, searchText);
}
} else {
return 'Not Found';
}
}
};
And My data is like this:
import { treeData } from './DdrTreeDropdown.types';
export const menu: treeData[] = [
{
name: 'Web Project',
children: [
{
name: 'NextJS',
children: [
{
name: 'MongoDB',
},
{
name: 'Backend',
children: [
{
name: 'NodeJS',
},
],
},
],
},
{
name: 'ReactJS',
children: [
{
name: 'Express',
},
{
name: 'mysql',
children: [
{
name: 'jwt',
},
],
},
],
},
],
},
{
name: 'lorem project',
children: [
{
name: 'Vue Js',
children: [
{
name: 'Oracle Db',
},
{
name: 'JDBC',
children: [
{
name: 'Java',
},
],
},
],
},
{
name: 'ReactJS',
children: [
{
name: 'Express',
},
{
name: 'mysql',
children: [
{
name: 'jwt',
},
],
},
],
},
],
},
];
The sandbox link of the component is here:
https://codesandbox.io/s/upbeat-feynman-89ozi?file=/src/styles.ts
I haven't looked at the context that this is used in, so apologies if I'm missing something about how this is supposed to work. I've assumed that you can call setFound after running this function based on whether it finds anything or not and that it only needs to return one value. But hopefully this helps.
const menu = [{"name":"Web Project","children":[{"name":"NextJS","children":[{"name":"MongoDB"},{"name":"Backend","children":[{"name":"NodeJS"}]}]},{"name":"ReactJS","children":[{"name":"Express"},{"name":"mysql","children":[{"name":"jwt"}]}]}]},{"name":"lorem project","children":[{"name":"Vue Js","children":[{"name":"Oracle Db"},{"name":"JDBC","children":[{"name":"Java"}]}]},{"name":"ReactJS","children":[{"name":"Express"},{"name":"mysql","children":[{"name":"jwt"}]}]}]}];
const searchFunction = (menu, searchText) => {
let result;
for(let i = 0; i < menu.length; i++) {
if(menu[i].name.includes(searchText)) {
return menu[i].name;
} else if(menu[i].children !== undefined) {
result = searchFunction(menu[i].children, searchText);
if(result) return result;
}
}
return null;
};
console.log(searchFunction(menu, 'NextJS'));
console.log(searchFunction(menu, 'jwt'));
console.log(searchFunction(menu, 'foo'));
Looking at why the current version doesn't work, I think it goes something like this:
Let's take 'jwt' as the searchText.
We start in the 'Web Project' object, the name does not match, so we go to the else if block (BTW, we can never reach the else block as the else if condition is the opposite of the if condition).
The 'Web Project' object does have children so we will return from the new call to searchFunction; notice that 'lorem project' can never be reached as we will (regardless of the result) return the value of searchFunction and skip the rest of the loop.
Inside of our new and subsequent calls to searchFunction the same is going to happen until we find either a matching item or an item without children.
If we get to an item without children the the loop will successfully carry on to the siblings of the item.
If it doesn't find a match or an item with children it will exit the for loop and return undefined up the chain to the caller of the initial searchFunction.

How to search within the nested array of objects in javascript?

i want to search a for a string say for example "hello" within 'name' in array of objects. The data structure is like the one below,
[{name:'hello', value: 'value', children: [{ name:'world', value: 'something'}]},
{name:'somename', value: 'value2', children: [{name: 'hello', value: 'value3', children: [{name: 'anothername', value: 'value4'}]},
{name: 'new', value: 'value5'}];
So from the above mentioned data structure, if the search query is say 'hello' i want to check through 'name' field of each object. also check within children 'name' field of each object. Some object may or may not have children and nested children too. I want to retreive the objects that have matched the search query.
For example if my search query is 'hello' then the expected output is as below,
[{name:'hello', value: 'value', children: [{ name:'world', value: 'something'}]},
{name:'somename', value: 'value2', children: [{name: 'hello', value: 'value3', children: [{name: 'anothername', value: 'value4'}]},
i have tried using the below search method but that doesnot search within children and nested children.
search = (query, listitems => {
if (!query) {
return listitems;
}
query = query.toLowerCase();
const results = [];
let counter;
let childcounter;
listitem.forEach((listitem) => {
counter = 0;
childcounter = 0;
if (listitem['name'].toLowerCase().indexOf(query) > -1)
{
counter++;
if (listitem.children)
{
listitem.children.forEach ((child) => {
if (child['name'].toLowerCase().indexOf(query) > -1)
childcounter++;
});
}
listitem.counter = counter;
listitem.childcounter = childcounter;
results.push(listitem);
}
return result
});
How can i do it. could someone help me with it. Thanks.

Categories

Resources