In which elements is the selected element? - javascript

I have an array. The elements in the array represent the menu elements. I want to create "breadcrumb" according to the menu item I selected. However, it provides errors dynamically after 3 depth while working.
// My Array
const menuArray = [{
"label": "Dashboard"
},
{
"label": "Products",
"items": [{
"label": "All Products"
},
{
"label": "New Product"
},
{
"label": "Product Categories"
}
]
},
{
"label": "Posts",
"items": [{
"label": "All Posts"
},
{
"label": "New Post"
},
{
"label": "Post Categories"
}
]
},
{
"label": "Sliders"
},
{
"label": "Settings",
"items": [{
"label": "General Settings"
},
{
"label": "User",
"items": [{
"label": "Your Profile"
},
{
"label": "Edit Profile"
}
]
},
{
"label": "Social Settings"
},
{
"label": "Link Settings"
}
]
}
];
// The function I experiment with
writeParent(event, arr) {
let ct = 0;
let found = false;
let parentsLine = [];
arr.some((e) => {
parentsLine = [];
let curr = e;
for (curr; curr.items != null; curr = curr.items[0]) {
if (event.label == curr.label) {
found = true;
return true;
}
parentsLine.push(curr.label);
}
if (event.label == curr.label) {
found = true;
return true;
}
});
if (found) {
return parentsLine;
} else {
return 'ERR: elm not found';
}
}
console.log(writeParent({
"label": "Edit Profile"
}, menuArray));
For example, if the element I selected is;
{
"label": "New Post"
}
I want to get;
[
{
"label": "Posts"
},
{
"label": "New Post"
}
]
or
if the element I selected is;
{
"label": "Edit Profile"
}
I want to get;
[
{
"label": "Settings"
},
{
"label": "User"
},
{
"label": "Edit Profile"
}
]
I didn't know how to find the parent of the selected element. How can I do that?

I've solved the problem.
menuArray = [{
"label": "Dashboard"
},
{
"label": "Products",
"items": [{
"label": "All Products"
},
{
"label": "New Product"
},
{
"label": "Product Categories"
}
]
},
{
"label": "Posts",
"items": [{
"label": "All Posts"
},
{
"label": "New Post"
},
{
"label": "Post Categories"
}
]
},
{
"label": "Sliders"
},
{
"label": "Settings",
"items": [{
"label": "General Settings"
},
{
"label": "User",
"items": [{
"label": "Your Profile"
},
{
"label": "Edit Profile"
}
]
},
{
"label": "Social Settings"
},
{
"label": "Link Settings"
}
]
}
];
function find(array, event) {
if (typeof array != 'undefined') {
for (let i = 0; i < array.length; i++) {
if (array[i].label == event.label) return [event.label];
let a = this.find(array[i].items, event);
if (a != null) {
a.unshift(array[i].label);
return a;
}
}
}
return null;
}
console.log(find(menuArray, { "label": "Edit Profile" }));

Related

How to retrieve and process the data from the open dialog form?

I'm trying to process the response data in the open dialog but got stuck in this the retrieval.
I followed the step by step procedure given in this link: https://developers.google.com/chat/how-tos/dialogs but unfortunately, it didn't work as well.
Here is the sample code:
My goal is to get the data from the dialog form then process it. My pain point is in the code: event.common.formInputs.firstnumber.stringInputs.value[0] where it returns undefined reading value.
function openDialog(event) {
return {
"action_response": {
"type": "DIALOG",
"dialog_action": {
"dialog": {
"body": {
"sections": [
{
"header": "Addition Calculator:",
"widgets": [
{
"textInput": {
"label": "First Number",
"type": "SINGLE_LINE",
"name": "firstnumber"
}
},
{
"textInput": {
"label": "Second Number",
"type": "SINGLE_LINE",
"name": "secondnumber"
}
},
{
"textInput": {
"label": "Third Number",
"type": "SINGLE_LINE",
"name": "thirdnumber"
}
},
{
"buttonList": {
"buttons": [
{
"text": "Submit",
"onClick": {
"action": {
"function": "giveAnswer"
}
}
}
]
},
"horizontalAlignment": "END"
}
]
}
]
}
}
}
}
};
}
function giveAnswer(event) {
var firstterm = parseFloat(event.common.formInputs.firstnumber.stringInputs.value[0])
var secondterm = parseFloat(event.common.formInputs.secondnumber.stringInputs.value[0])
var thirdterm = parseFloat(event.common.formInputs.thirdnumber.stringInputs.value[0])
var sum = firstterm+secondterm+thirdterm
return {
"cardsV2": [{
"cardId": "addContact",
"card": {
"header": {
"title": "The SUM is:",
"subtitle": "Answer",
"imageUrl": "https://images.emojiterra.com/google/noto-emoji/v2.034/128px/1f4f1.png",
"imageType": "SQUARE"
},
"sections": [
{
"widgets": [
{
"textParagraph": {
"text": sum
}
}
]
}
]
}
}
]
}
}
I tried the example in here but didn't work as well. https://developers.google.com/chat/how-tos/dialogs#receive_form_data_from_dialogs

add new key/value to each object inside a huge deeply nested objects

I have a huge object, with almost 50k lines.
I need to add in each object new key with the current path of the node
Example:
let obj = {
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"title": "Método:",
"data": [{
"title": "Procedimento 1",
"data": [{
"title": "CONTRASTE"
},
{
"title": "CONTRASTE 2"
}
]
},
{
"title": "Procedimento 2",
"data": [{
"title": "CONTRASTE 3"
},
{
"title": "CONTRASTE 4"
}
]
}
]
}]
}
And I need to change my object to return this:
obj = {
"path": "$",
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"path": "$.data.0",
"title": "Método:",
"data": [{
"path": "$.data.0.data.0",
"title": "Procedimento 1",
"data": [{
"path": "$.data.0.data.0.data.0",
"title": "CONTRASTE"
},
{
"path": "$.data.0.data.0.data.1",
"title": "CONTRASTE 2"
}
]
},
{
"path": "$.data.0.data.1",
"title": "Procedimento 2",
"data": [{
"path": "$.data.0.data.1.data.0",
"title": "CONTRASTE 3"
},
{
"path": "$.data.0.data.1.data.1",
"title": "CONTRASTE 4"
}
]
}
]
}]
}
If you notice, i added the key path inside each object for key data, with the current path of the node. This is what I need.
All my object are much bigger then this example, with much more nested objects
Performant version in case you have to deal with large files
const data = {
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"title": "Método:",
"data": [{
"title": "Procedimento 1",
"data": [{
"title": "CONTRASTE"
},
{
"title": "CONTRASTE 2"
}
]
},
{
"title": "Procedimento 2",
"data": [{
"title": "CONTRASTE 3"
},
{
"title": "CONTRASTE 4"
}
]
}
]
}]
}
function PathUpdate(data, path) {
data.path = path;
const nd = data.data;
if (nd == null) return;
for (let i = 0; i < nd.length; i++) {
PathUpdate(nd[i], `${path}.data.${i}`);
}
}
console.log("before", { data });
PathUpdate(data, "$");
console.log("after", { data });
const data = {
title: "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
type: "template",
data: [
{
title: "Método:",
type: "top-level-component",
data: [
{
title: "Procedimento",
type: "navigation",
normal: "CONTRASTE",
checked: true,
data: [
{
type: "single-selection",
title: "CONTRASTE",
},
{
type: "single-selection",
title: "CONTRASTE 2",
},
],
},
{
title: "Procedimento 2",
type: "navigation",
normal: "CONTRASTE",
checked: false,
data: [
{
type: "single-selection",
title: "CONTRASTE 3",
},
{
type: "single-selection",
title: "CONTRASTE 4",
},
],
},
],
},
],
};
function addPathToObj(obj, path) {
obj.path = path;
for (const [key, value] of Object.entries(obj)) {
if (Array.isArray(value)) {
value.forEach((item, index) => {
addPathToObj(item, `${path}.data.${index}`);
});
}
}
}
addPathToObj(data, "$");
console.log(data);

Reorder an array from a specific data

I have absolutely no idea of which title I could write.
Actually, here is what I get from API :
[
{
"order": 1,
"role": {
"label": "singer"
},
"artist": {
"name": "AaRON"
}
},
{
"order": 1,
"role": {
"label": "author"
},
"artist": {
"name": "Simon Buret"
}
},
{
"order": 2,
"role": {
"label": "author"
},
"artist": {
"name": "Olivier Coursier"
}
},
{
"order": 1,
"role": {
"label": "composer"
},
"artist": {
"name": "John Doe"
}
}
]
And here is what I need to send :
"artist": {
"singer": [
"AaRON"
],
"author": [
"Simon Buret",
"Olivier Coursier"
]
}
Of course, the order property must be taken in account.
Example : Simon Buret is the first item because he has the order set to 1.
I have absolutely no idea how to implement that, I just did a map, but don't know what to put inside :/
this.artistControl.controls.map(artistControl => {
...
});
Is there a way to do what I need ?
Does this work for you:
let arr = [
{ "order": 1, "role": { "label": "singer" }, "artist": { "name": "AaRON" } },
{ "order": 1, "role": { "label": "author" }, "artist": { "name": "Simon Buret" } },
{ "order": 2, "role": { "label": "author" }, "artist": { "name": "Olivier Coursier" } },
{ "order": 1, "role": { "label": "composer" }, "artist": { "name": "John Doe" } }
];
let obj = {'artist': {}};
arr.forEach(a => {
obj['artist'][a.role.label] = obj['artist'][a.role.label] || [];
obj['artist'][a.role.label][a.order-1] = a.artist.name;
});
console.log(obj);
You could use reduce method with object as a accumulator param and then check if the key doesn't exist create it with empty array as value and then add names by order.
const data = [{"order":1,"role":{"label":"singer"},"artist":{"name":"AaRON"}},{"order":1,"role":{"label":"author"},"artist":{"name":"Simon Buret"}},{"order":2,"role":{"label":"author"},"artist":{"name":"Olivier Coursier"}},{"order":1,"role":{"label":"composer"},"artist":{"name":"John Doe"}}]
const result = data.reduce((r, {
role: { label },
artist: { name },
order
}) => {
if (name) {
if (!r[label]) r[label] = [];
r[label][order - 1] = name;
}
return r;
}, {})
console.log(result)
const array = [{"order":1,"role":{"label":"singer"},"artist":{"name":"AaRON"}},{"order":1,"role":{"label":"author"},"artist":{"name":"Simon Buret"}},{"order":2,"role":{"label":"author"},"artist":{"name":"Olivier Coursier"}},{"order":1,"role":{"label":"composer"},"artist":{"name":"John Doe"}}];
const result = array
.sort((item1, item2) => item1.order - item2.order)
.reduce((acc, { role, artist }) => ({
...acc,
artist: {
...acc.artist,
[role.label]: [
...(acc.artist[role.label] || []),
artist.name,
],
},
}), { artist: {} });
console.log(result);
Here is another approach with es5
const data = [{ "order": 1, "role": { "label": "singer" }, "artist": { "name": "AaRON" } }, { "order": 1, "role": { "label": "author" }, "artist": { "name": "Simon Buret" } }, { "order": 2, "role": { "label": "author" }, "artist": { "name": "Olivier Coursier" } }, { "order": 1, "role": { "label": "composer" }, "artist": { "name": "John Doe" } }];
var result = data.reduce(function(map, obj) {
map["artist"] = map["artist"] || {};
if (obj.role.label === 'author' || obj.role.label === 'singer') {
map["artist"][obj.role.label] = map["artist"][obj.role.label] || [];
map["artist"][obj.role.label][obj.order - 1] = obj.artist.name;
}
return map;
}, {});
console.log(result)

Sub-grouping array of objects inside of sub-array of main array

I have an array like this
[
{
"id": 1,
"name": "Personal Information",
"TabFields": [
{
"name": "First Name",
"field": {
"code": "personFirstName"
}
},
{
"name": "Gender",
"field": {
"code": "personGenderD"
}
},
{
"name": "Last Name",
"field": {
"code": "personLastName"
}
},
{
"name": "Mobile Number",
"field": {
"code": "mobileNumber"
}
},
{
"name": "Email Address",
"field": {
"code": "emailAddress"
}
}
]
}
]
What I need is to group the objects inside the TabFields to their respective TAB (PERSONAL_INFORMATION, CONTACT_DETAILS) by code value inside the field object
The object
"name": "First Name",
"field": {
"code": "personFirstName"
}
"name": "Gender",
"field": {
"code": "personGenderD"
}
"name": "Last Name",
"field": {
"code": "personLastName"
}
is belong to PERSONAL_INFORMATION and the object
"name": "Mobile Number",
"field": {
"code": "mobileNumber"
}
"name": "Email Address",
"field": {
"code": "emailAddress"
}
is belong to CONTACT_DETAILS. So the output would be
[
{
"id": 1,
"name": "Personal Information",
"TabFields": [
{
"label": "PERSONAL_INFORMATION",
"code": "PERSONAL_INFORMATION",
"fields": [
{
"name": "First Name",
"field": {
"code": "personFirstName"
}
},
{
"name": "Gender",
"field": {
"code": "personGenderD"
}
},
{
"name": "Last Name",
"field": {
"code": "personLastName"
}
}
]
},
{
"label": "CONTACT_DETAILS",
"code": "PERSONAL_INFORMATION",
"fields": [
{
"name": "Mobile Number",
"field": {
"code": "mobileNumber"
}
},
{
"name": "Email Address",
"field": {
"code": "emailAddress"
}
}
]
}
]
}
]
How to do it in javascript?
You can also do this with map:
var arr=[ { "id": 1, "name": "Personal Information", "TabFields": [ { "name": "First Name", "field": { "code": "personFirstName" } }, { "name": "Gender", "field": { "code": "personGenderD" } }, { "name": "Last Name", "field": { "code": "personLastName" } }, { "name": "Mobile Number", "field": { "code": "mobileNumber" } }, { "name": "Email Address", "field": { "code": "emailAddress" } } ] }];
personalContact = ["Mobile Number", "Email Address"];
result = arr.map(val=>{
personalInfo = { label:'personal', code:val.name, fields:val.TabFields.filter(k=>!personalContact.includes(k.name))};
contactInfo = { label:'contact', code:val.name, fields:val.TabFields.filter(k=>personalContact.includes(k.name))};
val.TabFields = [personalInfo, contactInfo];
return val;
});
console.log(result);
Idea would be to have an array which should distinguish between the contact details and personal details using which you can apply filter to get the data.
You can express transformations simply with a library I created, rubico.
const { pipe, fork, assign, get, map, filter } = require('rubico')
const PERSONAL_INFORMATION_FIELDS = new Set(['First Name', 'Gender', 'Last Name'])
const CONTACT_DETAILS_FIELDS = new Set(['Mobile Number', 'Email Address'])
// [datum] => [datum_with_grouped_TabFields]
const groupTabFields = assign({ // reassign TabFields to new grouped TabFields
TabFields: fork([
fork({
label: () => 'PERSONAL_INFORMATION',
code: () => 'PERSONAL_INFORMATION',
fields: pipe([
get('TabFields'), // datum => datum.TabFields
filter(pipe([ // FILTER: for each TabField of TabFields
get('name'), // TabField => TabField.name
field => PERSONAL_INFORMATION_FIELDS.has(field), // check if PERSONAL_INFORMATION_FIELDS has name
])),
]),
}),
fork({ // same as above but with contact details
label: () => 'CONTACT_DETAILS',
code: () => 'CONTACT_DETAILS',
fields: pipe([
get('TabFields'),
filter(pipe([
get('name'),
field => CONTACT_DETAILS_FIELDS.has(field)
])),
]),
}),
]),
})
x = map(groupTabFields)(data)
console.log(JSON.stringify(x, null, 2)) // output is what you wanted
I've added some comments, but for a deeper understanding of the library and code I've given you, I recommend reading the intuition and then reading the docs

Iterate and group the objects using map function

Check for the decimal id and group them accordingly.
Below are the sample and recommended JSON's
Sample JSON
{
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
}
Would like to iterate and Re-structure the above JSON into below recommended format.
Logic: Should check the id(with and without decimals) and group them based on the number.
For Example:
1, 1.1, 1.2.3, 1.4.5 => data1: [{id: 1},{id: 1.1}....]
2, 2.3, 2.3.4 => data2: [{id: 2},{id: 2.3}....]
3, 3.1 => data3: [{id: 3},{id: 3.1}]
Recommended JSON
{
"results": [
{
"data1": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
}
]
},
{
"data2": [
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
}
]
},
{
"data3": [
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
}
]
},
{
"data4": [
{
"name": "Download",
"id": "4.2"
}
]
}
]
}
I have tried the below solution but it doesn't group the object
var formatedJSON = [];
results.map(function(d,i) {
formatedJSON.push({
[data+i]: d
})
});
Thanks in advance.
You can use reduce like this. The idea is to create a key-value pair for each data1, data2 etc so that values in this object are the values you need in the final array. Then use Object.values to get those as an array.
const sampleJson = {"results":[{"name":"Download","id":"1.1.1"},{"name":"Download","id":"1.2"},{"name":"Download","id":"1.3.2"},{"name":"Download","id":"2"},{"name":"Download","id":"2.3"},{"name":"Download","id":"3.2"},{"name":"Download","id":"3.5"},{"name":"Download","id":"4.2"}]}
const grouped = sampleJson.results.reduce((a, v) => {
const key = `data${parseInt(v.id)}`;
(a[key] = a[key] || {[key]: []})[key].push(v);
return a;
},{});
console.log({results: Object.values(grouped)})
One liner / Code-golf:
let s={"results":[{"name":"Download","id":"1.1.1"},{"name":"Download","id":"1.2"},{"name":"Download","id":"1.3.2"},{"name":"Download","id":"2"},{"name":"Download","id":"2.3"},{"name":"Download","id":"3.2"},{"name":"Download","id":"3.5"},{"name":"Download","id":"4.2"}]},k;
console.log({results:Object.values(s.results.reduce((a,v)=>(k=`data${parseInt(v.id)}`,(a[k] = a[k]||{[k]:[]})[k].push(v),a),{}))})
Here you go:
var data = {
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
};
let newSet = new Set();
data.results.forEach(e => {
let key = e.id.substring(0, e.id.indexOf('.'));
console.log(key);
if (newSet.has(key) == false) {
newSet.add(key);
newSet[key] = [];
}
newSet[key].push(e.id);
});
console.log(newSet);
Here's how you'd do it:
var data = {
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
};
var newData = {
"results": {}
};
data.results.forEach(item => {
var num = item.id.slice(0, 1);
if (newData.results["data" + num]) {
newData.results["data" + num].push(item);
} else {
newData.results["data" + num] = [item];
}
})
data = newData;
console.log(data);
What this does is it iterates through each item in results, gets the number at the front of this item's id, and checks if an array of the name data-{num} exists. If the array exists, it's pushed. If it doesn't exist, it's created with the item.
let input = getInput();
let output = input.reduce((acc, curr)=>{
let {id} = curr;
let majorVersion = 'name' + id.split('.')[0];
if(!acc[majorVersion]) acc[majorVersion]= [];
acc[majorVersion].push(curr);
return acc;
},{})
console.log(output)
function getInput(){
return [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
}
One solution with RegEx for finer control as it would differentiate easily between 1 and 11.
Also this will make sure that even if the same version comes in end(say 1.9 in end) it will put it back in data1.
let newArr2 = ({ results }) =>
results.reduce((acc, item) => {
let key = "data" + /^(\d+)\.?.*/.exec(item.id)[1];
let found = acc.find(i => key in i);
found ? found[key].push(item) : acc.push({ [key]: [item] });
return acc;
}, []);

Categories