I'm trying to merge two javascript objects that has inside of it arrays and other elements. Let me give you an example.
{
"addresses": [
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai1#gmail.com"
},
{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839332"
},
{
"type": "email",
"tags": [
"Mãe"
],
"address": "johndoemae1#gmail.com"
},
{
"type": "email",
"tags": [
"Aluno"
],
"address": "johndoealuno1#gmail.com"
}
],
"class": [
"Sala 1",
"Sala 2",
"Sala 3"
],
"fullname": "John Doe 1",
"eid": "2",
"invisible": true,
"see_all": false
},
{
"addresses": [
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai2#gmail.com"
},
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai3#gmail.com"
},
{
"type": "phone",
"tags": [
"Pai"
],
"address": "5519985504400"
},
{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839333"
},
{
"type": "email",
"tags": [
"Mãe"
],
"address": "11 983340440"
},
{
"type": "email",
"tags": [
"Aluno"
],
"address": ""
}
],
"class": [
"Sala 4",
"Sala 5",
"Sala 6"
],
"fullname": "John Doe 1",
"eid": "2",
"invisible": false,
"see_all": true
}
As you can see, we can have arrays inside with some strings in those arrays.
I've tried to do it using some recursion, but had no success.
function mergeObjects(target, source){
var item, tItem, o, idx;
if (typeof source == 'undefined') {
return source;
} else if (typeof target == 'undefined') {
return target;
}
for (var prop in source) {
item = source[prop];
//check if the first element is indeed an object.
if (typeof item == 'object' && item !== null) {
//if the first item is an array
if (_.isArray(item) && item.length) {
//dealing with array of primitives
if (typeof item[0] != 'object') {
item.forEach(function(conteudo){
//push to the target all the elements;
target[prop].push(conteudo);
});
}else{
//dealing with array of objects;
for(var attr in item){
idx = {};
tItem = target[attr]
mergeObjects(tItem,item);
}
}
}//if its a normal object
else {
// deal with object
mergeObjects(target[prop],item);
}
} else {
// item is a primitive, just copy it over
target[prop] = item;
}
}
return target;
}
I Expected this:
{
"addresses": [
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai2#gmail.com"
},
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai3#gmail.com"
},
{
"type": "phone",
"tags": [
"Pai"
],
"address": "5519985504400"
},
{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839333"
},
{
"type": "email",
"tags": [
"Mãe"
],
"address": "11 983340440"
},
{
"type": "email",
"tags": [
"Aluno"
],
"address": ""
}
],
"class": [
"Sala 4",
"Sala 5",
"Sala 6",
"Sala 1",
"Sala 2",
"Sala 3"
],
"fullname": "John Doe 1",
"eid": "2",
"invisible": true,
"see_all": false
}
"fullname": "John Doe 1",
"eid": "1234",
"classes": [
"Sala 1",
"Sala 2",
"Sala 3",
"Sala 4",
"Sala 5",
"Sala 6"
],
"addresses": [{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839332"
}, {
"type": "email",
"tags": [
"Mãe"
],
"address": "johndoemae1#gmail.com"
}, {
"type": "email",
"tags": [
"Aluno"
],
"address": "johndoealuno1#gmail.com"
}, {
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai2#gmail.com"
}, {
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai3#gmail.com"
}, {
"type": "phone",
"tags": [
"Pai"
],
"address": "5519985504400"
}, {
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839333"
}],
"invisible": true,
"see_all": true
}
But what i got was this, as you can see, some email elements are missing.
{
"addresses": [
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai2#gmail.com"
},
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai3#gmail.com"
},
{
"type": "phone",
"tags": [
"Pai"
],
"address": "5519985504400"
},
{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839333"
},
{
"type": "email",
"tags": [
"Mãe"
],
"address": "11 983340440"
},
{
"type": "email",
"tags": [
"Aluno"
],
"address": ""
}
],
"class": [
"Sala 4",
"Sala 5",
"Sala 6",
"Sala 1",
"Sala 2",
"Sala 3"
],
"fullname": "John Doe 1",
"eid": "2",
"invisible": true,
"see_all": false
}
Order of elements is not a problem.
Which point of the recursion tree did i miss?
Short answer: you have to merge the arrays yourself first. Or you can use something nice like Lodash's mergeWidth Ramda's R.mergeWith (see below for sample code for Ramda).
You want something like the native Object.assign (limited browser support, so it will have to be polyfilled) or whatever merge your JS library has.
The problem you're running into is how all of these merge implementations handle duplicate keys. Usually the key will be set to the last value passed in:
var thing1 = {
someProperty: 'foo'
};
var thing2 = {
someProperty: 'bar'
};
var result1 = Object.assign({}, thing1, thing2);
// -> {someProperty: 'bar'} (set to the last value passed in, in thing2)
var result2 = Object.assign({}, thing2, thing1);
// -> {someProperty: 'foo'} (again set to the last value passed in, in thing1)
// Make the Stackoverflow snippet display the output.
document.body.innerHTML += JSON.stringify(result1, null, 2);
document.body.innerHTML += '<br>' + JSON.stringify(result2, null, 2);
Works the same way with your example, except the property is a more complicated array. It's just being set to the last array passed in:
var thing1 = {
someList: [1, 2, 3]
};
var thing2 = {
someList: [4, 5, 6]
};
var result = Object.assign({}, thing1, thing2);
// -> {someList: [4, 5, 6]}
// Make the Stackoverflow snippet display the output.
document.body.innerHTML = JSON.stringify(result, null, 2);
If you use something nice like Ramda, you can merge and specify a function to control the behavior when keys are equal, like in your case. Here we can check if the value is an array, then concatenate if so. Otherwise, return the latest value (as described above):
var thing1 = {someList: [1, 2, 3]};
var thing2 = {someList: [4, 5, 6]};
var dupeMergeFn = function(a, b) {
return (Array.isArray(a)) ? a.concat(b) : b;
};
var result = R.mergeWith(dupeMergeFn, thing1, thing2);
// Make the Stackoverflow snippet display the output.
document.body.innerHTML = JSON.stringify(result, null, 2);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.19.1/ramda.min.js"></script>
Related
I am still fairly new to JavaScript and need help with a task I am trying to accomplish.
I have an array of objects like this:
const data =
{
"Total_packages": {
"package1": {
"tags": [
"kj21",
"j1",
"sj2",
"z1"
],
"expectedResponse": [
{
"firstName": "Name",
"lastName": "lastName",
"purchase": [
{
"title": "title",
"category": [
"a",
"b",
"c"
]
}
]
}
]
},
"package2": {
"tags": [
"s2",
"dsd3",
"mhg",
"sz7"
],
"expectedResponse": [
{
"firstName": "Name1",
"lastName": "lastName1",
"purchase": [
{
"title": "title1",
"category": [
"a1",
"b1",
"c1"
]
}
]
}
]
},
"package3": {
"tags": [
"s21",
"dsd31",
"mhg1",
"sz71"
],
"expectedResponse": [
{
"firstName": "Name2",
"lastName": "lastName2",
"purchase": [
{
"title": "title2",
"category": [
"a2",
"b2",
"c2"
]
}
]
}
]
},
"package4": {
"tags": [
"s22",
"dsd32",
"mhg2",
"sz72"
],
"expectedResponse": [
{
"firstName": "Name3",
"lastName": "lastName3",
"purchase": [
{
"title": "title3",
"category": [
"a3",
"b3",
"c3"
]
}
]
}
]
},
"package5": {
"tags": [
"s22",
"dsd32",
"mhg2",
"sz72"
],
"expectedResponse": [
{
"firstName": "Name4",
"lastName": "lastName4",
"purchase": [
{
"title": "title4",
"category": [
"a4",
"b4",
"c4"
]
}
]
}
]
}
}
}
var arrRand = genNum(data, 3);
console.log(arrRand);
function genNum(data, loop='') {
var list = [];
var arrayOfTags = Object.entries(data.Total_packages).reduce((acc, [k, v]) => {
if (v.tags) acc = acc.concat(v.tags.map(t => ({tag: t, response: v.expectedResponse})));
return acc;
}, []);
for (var i = 0; i < loop; i++){
var randomIndex = Math.floor(Math.random() * arrayOfTags.length);
var randomTag = arrayOfTags[randomIndex];
list.push(randomTag);
}
return list;
}
I then access the values I need by doing something like arrRand[0].tag and arrRand[0].response.
Often times I get duplicate responses from the method such as following and it becomes problematic:
[
{
"tag": "s22",
"response": [
{
"firstName": "Name4",
"lastName": "lastName4",
"purchase": [
{
"title": "title4",
"category": [
"a4",
"b4",
"c4"
]
}
]
}
]
},
{
"tag": "dsd31",
"response": [
{
"firstName": "Name2",
"lastName": "lastName2",
"purchase": [
{
"title": "title2",
"category": [
"a2",
"b2",
"c2"
]
}
]
}
]
},
{
"tag": "dsd31",
"response": [
{
"firstName": "Name2",
"lastName": "lastName2",
"purchase": [
{
"title": "title2",
"category": [
"a2",
"b2",
"c2"
]
}
]
}
]
}
]
My goal is to send API requests with a random "tags" value from above and then match the response I get from the call to the expectedResponse part of the data.
My initial thought was to do something like:
data.Total_packages.tags[Math.floor(Math.random() * data.Total_packages.tags.length)];
However, I can't call on "tags" without traversing through its parent i.e "package1" or "package2", so then it won't be random anymore.
I know there is probably a very simple way to do it that I am not getting. Any advice would be appreciated.
You could build an array from the various tags elements, and use that to do random things.
const data =
{
"Total_packages": {
"package1": {
"tags": [
"kj21",
"j1",
"sj2",
"z1"
],
"expectedResponse": [
{
"firstName": "Name",
"lastName": "lastName",
"purchase": [
{
"title": "title",
"category": [
"a",
"b",
"c"
]
}
]
}
]
},
"package2": {
"tags": [
"s2",
"dsd3",
"mhg",
"sz7"
],
"expectedResponse": [
{
"firstName": "Name1",
"lastName": "lastName1",
"purchase": [
{
"title": "title1",
"category": [
"a1",
"b1",
"c1"
]
}
]
}
]
}
}
}
const arrayOfTags = Object.entries(data.Total_packages).reduce((acc, [k, v]) => {
if (v.tags) acc = acc.concat(v.tags.map(t => ({tag: t, response: v.expectedResponse})));
return acc;
}, []);
const randomIndex = Math.floor(Math.random() * arrayOfTags.length);
const randomTag = arrayOfTags[randomIndex];
console.log(randomTag.tag, randomTag.response);
You will need to mine the tags, put them together into an array and randomize the index, finally get the value there. The solution below assumes that your tags are all arrays inside data.Total_packages[whateverpackage]
const data =
{
"Total_packages": {
"package1": {
"tags": [
"kj21",
"j1",
"sj2",
"z1"
],
"expectedResponse": [
{
"firstName": "Name",
"lastName": "lastName",
"purchase": [
{
"title": "title",
"category": [
"a",
"b",
"c"
]
}
]
}
]
},
"package2": {
"tags": [
"s2",
"dsd3",
"mhg",
"sz7"
],
"expectedResponse": [
{
"firstName": "Name1",
"lastName": "lastName1",
"purchase": [
{
"title": "title1",
"category": [
"a1",
"b1",
"c1"
]
}
]
}
]
}
}
}
let tags = [];
for (let key in data.Total_packages) {
if (data.Total_packages[key].tags) tags = tags.concat(data.Total_packages[key].tags);
}
console.log(tags[parseInt(tags.length * Math.random())]);
EDIT
In the comment section you have mentioned that you have duplicates of the form of
[
{
"tag": "s22",
"response": [
{
"firstName": "Name4",
"lastName": "lastName4",
"purchase": [
{
"title": "title4",
"category": [
"a4",
"b4",
"c4"
]
}
]
}
]
},
{
"tag": "dsd31",
"response": [
{
"firstName": "Name2",
"lastName": "lastName2",
"purchase": [
{
"title": "title2",
"category": [
"a2",
"b2",
"c2"
]
}
]
}
]
},
{
"tag": "dsd31",
"response": [
{
"firstName": "Name2",
"lastName": "lastName2",
"purchase": [
{
"title": "title2",
"category": [
"a2",
"b2",
"c2"
]
}
]
}
]
}
]
This is how you can get rid of duplicates:
let input = [
{
"tag": "s22",
"response": [
{
"firstName": "Name4",
"lastName": "lastName4",
"purchase": [
{
"title": "title4",
"category": [
"a4",
"b4",
"c4"
]
}
]
}
]
},
{
"tag": "dsd31",
"response": [
{
"firstName": "Name2",
"lastName": "lastName2",
"purchase": [
{
"title": "title2",
"category": [
"a2",
"b2",
"c2"
]
}
]
}
]
},
{
"tag": "dsd31",
"response": [
{
"firstName": "Name2",
"lastName": "lastName2",
"purchase": [
{
"title": "title2",
"category": [
"a2",
"b2",
"c2"
]
}
]
}
]
}
];
let output = input.filter((item, index) => {
return input.filter((item2, index2) => {
return ((item.tag === item2.tag) && (index2 < index));
}).length === 0;
});
console.log(output);
We search for items who have no matches on earlier indexes.
i saved all tags in a separate array and kept the ref of expectedResponse in the block. then it's a matter or randomly selecting one tag index and matching with the block expectedResponse index. probably needs some adjustment to the random/length but i hope it puts you in the right direction.
var tags = []
var block = Object.values(data.Total_packages).flat()
block.forEach(item => tags = [...tags, ...item.tags])
var index = tags[parseInt(tags.length * Math.random())]
console.log(block[Math.floor(tags.indexOf(index) / 4)].expectedResponse)
Ok, this one might be a doozy. I'm banging away but wonder if there's an elegant way to approach this.
I have an object of assets, each of which has some properties, as well as some number of sub-assets in either of two possible objects: assets and characteristics.
I also have a flat object with the defaults for each type of asset stored.
I would like to iterate through the object, detect the type of asset I'm looking at from the ID, load the properties from the flat defaults object, overwrite any of those that's present in the nested object, and return a new nested object that's got all the defaults, but is also updated with anything present in the original nested object.
For example, the nested object:
{
"id": "Bohemian Rhapsody",
"version": "0.10.1.5",
"manifest": "6s43qhuy53as980u08647ugp864q867-08d4svbn9uh54xc8vu",
"slug": "DarkShiftingBolt",
"visibility": "friends",
"locked": true,
"values": {"value0":2},
"assets": [
{
"id": "I see",
"assets": [
{
"id": "a little",
"name": "Queen",
"values": {
"value1": 1,
"value2": 3,
"value3": 2
},
"characteristics": [
{
"id": "silhouetto",
"assets": [
{
"id": "of a man",
"values": {
"value4": 3,
"value5": 1
},
"assets": [
{"id": "Scaramouche"}
]
}
]
}
],
"assets": [
{"id": "Scaramouche"}
]
},
{
"id": "will you",
"name": "Freddy",
"values": {
"value1": 1,
"value2": 0,
"value3": 3
},
"assets": [
{
"id": "do the",
"assets": [
{"id": "fandango"}
]
}
]
}
]
}
]
}
The flat defaults object:
{
"Bohemian Rhapsody": {
"visibility": "hidden",
"locked": false,
"values": {"value0":1},
},
"I see": {
"cost": 4
},
"a little": {
"values": {
"value2": 1,
"value4": 5
},
},
"silhouetto": {
"cost": 1
},
"of a man": {
"genre": "opera"
},
"Scaramouche": {
"rank": 3
},
"will you": {
"values": {
"value4": 0
},
},
"do the": {
"signature": [[4,4],[2,4],[6,8]]
},
"fandango": {
"records": ["thunderbolts","lightning"]
}
}
The desired output object:
{
"id": "Bohemian Rhapsody",
"version": "0.10.1.5",
"manifest": "6s43qhuy53as980u08647ugp864q867-08d4svbn9uh54xc8vu",
"slug": "DarkShiftingBolt",
"visibility": "hidden",
"locked": false,
"values": {"value0":1},
"assets": [
{
"id": "I see",
"cost": 4,
"assets": [
{
"id": "a little",
"name": "Queen",
"values": {
"value1": 1,
"value2": 1,
"value3": 2,
"value4": 5
},
"characteristics": [
{
"id": "silhouetto",
"assets": [
{
"id": "of a man",
"genre": "opera",
"values": {
"value4": 3,
"value5": 1
},
"assets": [
{
"id": "Scaramouche",
"rank": 3
}
]
}
]
}
],
"assets": [
{
"id": "Scaramouche",
"rank": 3
}
]
},
{
"id": "will you",
"name": "Freddy",
"values": {
"value1": 1,
"value2": 0,
"value3": 3,
"value4": 0
},
"assets": [
{
"id": "do the",
"signature": [[4,4],[2,4],[6,8]],
"assets": [
{
"id": "fandango",
"records": ["thunderbolts","lightning"]
}
]
}
]
}
]
}
]
}
What I'm trying is an object.keys recursive function that builds a new object from the properties it finds. I'm curious to know if there's a smarter way to go about it.
Got it thanks to #rayhatfield.
import * as merge from 'deepmerge';
this.manifest = (manifestData as any).default;
this.list = (listData as any).default;
this.list = this.assetIterate(this.list);
assetIterate(asset){
let id = asset.id;
let type = this.manifest.asset_catalog[id].type;
let newAsset = merge.all([this.manifest.asset_taxonomy[type],this.manifest.asset_catalog[id],asset])
Object.keys(asset).forEach((key) => {
if(key === "characteristics" || key === "assets"){
newAsset[key] = [...asset[key]]
newAsset[key].forEach((asset,index) => {
newAsset[key][index] = this.assetIterate(asset);
});
}
});
asset = {...newAsset}
return asset
}
Seems to work for all cases except a corner case in which a sub array needs to have indices replaced instead of concatenated, but I can special-case that when I actually make one of those.
I am trying to learn javascript reduce and map an I came across some difficulties.
I have an array with the following format. The id of the parent is same as the location_id of the child. I need to group the array into a nested format.
arr = [
{
"id": 4583211,
"name": "Location 1",
"location_id": null,
},
{
"id": 7458894,
"name": "Location 12",
"location_id": 4583211
},
{
"id": 7463953,
"name": "Location 13",
"location_id": 4583211
},
{
"id": 80302210,
"name": "Location 121",
"location_id": 7458894
},
{
"id": 80302219,
"name": "Location 122",
"location_id": 7458894
},
{
"id": 7464314,
"name": "Location 131",
"location_id": 7463953
},
{
"id": 4583216,
"name": "Location 2",
"location_id": null,
},
{
"id": 3566353,
"name": "Location 21",
"location_id": 4583216
},
]
This array should be grouped as:
result = [
{
"id": 4583211,
"name": "Location 1",
"locations": [
{
"id": 7458894,
"name": "Location 12",
"locations": [
{
"id": 80302210,
"name": "Location 121"
},
{
"id": 80302219,
"name": "Location 122"
}
]
},
{
"id": 7463953,
"name": "Location 13",
"locations": [
{
"id": 7464314,
"name": "Location 131"
}
]
}
]
},
{
"id": 4583216,
"name": "Location 2",
"locations": [
{
"id": 3566353,
"name": "Location 21"
}
]
}
]
I tried to group it using the following method found on SO but it gives different result.
result = arr.reduce(function (r, a) {
r[a.location_id] = r[a.location_id] || [];
r[a.location_id].push(a);
return r;
}, Object.create(null));
You could do this using reduce and recursion you just need to check if parent is equal to current elements location_id.
const data = [{"id":4583211,"name":"Location 1","location_id":null},{"id":7458894,"name":"Location 12","location_id":4583211},{"id":7463953,"name":"Location 13","location_id":4583211},{"id":80302210,"name":"Location 121","location_id":7458894},{"id":80302219,"name":"Location 122","location_id":7458894},{"id":7464314,"name":"Location 131","location_id":7463953},{"id":4583216,"name":"Location 2","location_id":null},{"id":3566353,"name":"Location 21","location_id":4583216}]
function create(data, parent = null) {
return data.reduce((r, e) => {
if(parent == e.location_id) {
const o = { id: e.id, name: e.name }
const children = create(data, e.id);
if(children.length) o.locations = children;
r.push(o)
}
return r
}, [])
}
console.log(create(data))
var cart =
[
{
"Items": "",
"category": "",
"contents":
[
{
"Apple iPhone": "222",
"French": "Bounjour",
"id": 1234,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag":"false"
}
]
},
{
"Items": "No 2",
"category": "2nd",
"contents":
[
{
"redmi": "333",
"French": "some text",
"id": 345787,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag":"true"
},
{
"samsung": "333",
"French": "some text",
"id": 86787876,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag":"disabled"
}
]
}
];
Can anyone help me to get the "id" value and "pricetag" value from the above JSON ? It is nested one and can be in different format. But in each, i need to extract id value and pricetag value. I tried so many things but not getting exact output. Can someone please help me ? Sorry for the bad formatting ..
use .map() to iterate and return the desired keys :
var cart = [{
"Items": "",
"category": "",
"contents": [{
"Apple iPhone": "222",
"French": "Bounjour",
"id": 1234,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag": "false"
}]
},
{
"Items": "No 2",
"category": "2nd",
"contents": [{
"redmi": "333",
"French": "some text",
"id": 345787,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag": "true"
},
{
"samsung": "333",
"French": "some text",
"id": 86787876,
"icon": "/images/bg.jpg",
"callback": "use()",
"pricetag": "disabled"
}
]
}
];
let values = cart.map((e) => {
return e.contents.map((a) => {
return {
id: a.id,
pricetag: a.pricetag
}
})
})
console.log(values)
This should work for you :
var items=[];
var some_var;
const map1 = cart.map(function(item){
const map2=item.contents.map(function(contentItem){
//some_var=contentItem.id;
return{
pricetag:contentItem.pricetag,
id:contentItem.id
}
})
items=items.concat(map2)
});
console.log(items);
Sample output:
[ { pricetag: 'false', id: 1234 },
{ pricetag: 'true', id: 345787 },
{ pricetag: 'disabled', id: 86787876 } ]
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;
}