I'm trying to display contacts in a table where it's possible to enter multiple contacts for the same address. I defined the settings for reactive table like this :
Template.masterlist.helpers({
settings: function() {
return {
collection: Prospects,
rowsPerPage: 10,
showFilter: true,
showColumnToggles: true,
fields: [
{
'key': 'address.streetNumber',
label: 'Street Number'
}, {
'key': 'address.streetName',
label: 'Street Name'
}, {
'key': 'address.streetApp',
label: 'App.'
}, {
'key': 'address.city',
label: 'City'
}, {
'key': 'address.province',
label: 'Province'
}, {
'key': 'address.postalCode',
label: 'Postal Code'
}, {
'key': 'contacts.0.name',
label: 'Name'
}, {
'key': 'contacts.0.phone',
label: 'Phone'
}, {
'key': 'contacts.0.email',
label: 'Email'
}, {
'key': 'contacts.0.notes',
label: 'Notes'
}
]
};
}
The problem is that it displays only the contact info for the first contact at this address I tried using [0] instead of just '0' but it didn't change anything.
Any idea?
Related
In a project that I'm working on, we're using the Angular library called formly to create our forms dynamically.
Currently, the form configuration is hardcoded as a Typescript object called mockForm. All of the properties in mockForm are hardcoded besides the options property in objects whose type property equals 'select':
mockForm
export const mockForm = {
name: 'root',
subSections: [
{
name: 'Client',
subSections: [
{
name: 'Contact Information'
},
{
name: 'Insurance Information'
}
]
},
{
name: 'Sales',
subSections: [
{
name: 'Overview',
subSections: [
{
name: 'Overview - A',
fields: [
{
key: 'fieldA1',
type: 'input',
templateOptions: {
label: 'A1',
required: true
}
},
{
key: 'fieldA2',
type: 'select',
templateOptions: {
label: 'A2',
required: true,
options: []
}
}
]
},
{
name: 'Overview - B',
fields: [
{
key: 'fieldB1',
type: 'input',
templateOptions: {
label: 'B1',
required: false
}
},
{
key: 'fieldB2',
type: 'select',
templateOptions: {
label: 'B2',
required: false,
options: []
}
}
]
}
]
}
]
}
]
};
I would like to populate the options property by using an API called which returns the following object:
API return
{
"multi_value_fields": {
"fieldA2": [
"froodian#outlook.com",
"gastown#sbcglobal.net",
"dgriffith#me.com",
"maradine#live.com",
"samavati#icloud.com",
"naupa#comcast.net"
],
"fieldB2": [
"<3m",
"<6m",
"<9m",
"<12m",
"+12m",
"N/A"
]
}
}
The object returned from the API call returns a JSON whose properties are the key values from mockForm whose property type equals 'select'; and the values of these JSON properties represent the dropdown options of the form.
The intended outcome should be the following:
export const mockForm = {
name: 'root',
subSections: [
{
name: 'Client',
subSections: [
{
name: 'Contact Information'
},
{
name: 'Insurance Information'
}
]
},
{
name: 'Sales',
subSections: [
{
name: 'Overview',
subSections: [
{
name: 'Overview - A',
fields: [
{
key: 'fieldA1',
type: 'input',
templateOptions: {
label: 'A1',
required: true
}
},
{
key: 'fieldA2',
type: 'select',
templateOptions: {
label: 'A2',
required: true,
options: [
"froodian#outlook.com",
"gastown#sbcglobal.net",
"dgriffith#me.com",
"maradine#live.com",
"samavati#icloud.com",
"naupa#comcast.net"
]
}
}
]
},
{
name: 'Overview - B',
fields: [
{
key: 'fieldB1',
type: 'input',
templateOptions: {
label: 'B1',
required: false
}
},
{
key: 'fieldB2',
type: 'select',
templateOptions: {
label: 'B2',
required: false,
options: [
"<3m",
"<6m",
"<9m",
"<12m",
"+12m",
"N/A"
]
}
}
]
}
]
}
]
}
]
};
I haven't experienced a scenario like this, and I'm not so sure on how to approach this (Should I start with the JSON properties and map back to mockForm? Would I need to manually iterate through mockForm in order to populate from the API call?)
your JSON mockForm is very typical.
If it remains the same then you must manually iterate over the bottom leaf i.e., mokeForm.subSections[1].subSections and then loop there to match the label & type.
Otherwise, you need to write parse which iterates all over mokeForm JSON & assign required options are respective places.
I want to convert an object from one format to another. So far my attempts at doing this recursively failed; either I'm getting a maximum stack exception or I'm unable to iterate over all paths.
Let's assume we have an object that lists questions and their answers. There may be N questions and M answers.
Object at start:
var before = {
item: 'Question 1',
id: '1',
type: 'Question',
items: [
{
item: 'Answer 1',
id: '1.1',
type: 'Answer',
items:
[
{
item: 'Question 2',
id: '1.1.1',
type: 'Question',
items: [
{
item: 'Answer 2.1',
id: '1.1.1.1',
type: 'Answer'
},
{
item: 'Answer 2.2',
id: '1.1.1.2',
type: 'Answer'
}
]
}
// ...
]
}, {
item: 'Answer 1',
id: '1.2',
type: 'Answer',
items:
[
{
item: 'Question 3',
id: '1.2.1',
type: 'Question',
items: [
{
item: 'Answer 3.1',
id: '1.2.1.1',
type: 'Answer'
},
{
item: 'Answer 3.2',
id: '1.2.1.2',
type: 'Answer'
}
]
}
// ...
]
}
// ...
]
}
Object how it should look like (wrap all in 'items' array; change key names 'item' to 'title', 'id' to 'key', remove 'type', add 'color' depending on 'type'):
var after = {
items: [
{
title: 'Question 1',
key: '1',
color: 'Red',
items: [
{
title: 'Answer 1',
key: '1.1',
color: 'Blue',
items:
[
{
title: 'Question 2',
key: '1.1.1',
color: 'Red',
items: [
{
title: 'Answer 2.1',
key: '1.1.1.1',
color: 'Blue'
},
{
title: 'Answer 2.2',
key: '1.1.1.2',
color: 'Blue'
}
]
}
// ...
]
}, {
title: 'Answer 1',
key: '1.2',
color: 'Blue',
items:
[
{
title: 'Question 3',
key: '1.2.1',
color: 'Red',
items: [
{
title: 'Answer 3.1',
key: '1.2.1.1',
color: 'Blue'
},
{
title: 'Answer 3.2',
key: '1.2.1.2',
color: 'Blue'
}
]
}
// ...
]
}
// ...
]
}
]
}
It seems easy enough, but I can't get it to work. This is how I tried to iterate:
function iter(o) {
for(let k in o) {
if (!(['item', 'items', 'id'].includes(k))) // My object contains a few more keys I don't want to go down further into
continue
if (o[k] !== null && typeof o[k] === 'object') {
iter(o[k]); // Max stack exception
return;
}
}
};
Thank you very much!
You could map the objects and rename the keys and map nested items.
const
iter = ({ item: title, id: key, type, items, ...o }) => ({
title,
key,
color: 'color' + key,
...o,
...(items && { items: items.map(iter) })
}),
before = { item: 'Question 1', id: '1', type: 'Question', items: [{ item: 'Answer 1', id: '1.1', type: 'Answer', items: [{ item: 'Question 2', id: '1.1.1', type: 'Question', items: [{ item: 'Answer 2.1', id: '1.1.1.1', type: 'Answer' }, { item: 'Answer 2.2', id: '1.1.1.2', type: 'Answer' }] }] }, { item: 'Answer 1', id: '1.2', type: 'Answer', items: [{ item: 'Question 3', id: '1.2.1', type: 'Question', items: [{ item: 'Answer 3.1', id: '1.2.1.1', type: 'Answer' }, { item: 'Answer 3.2', id: '1.2.1.2', type: 'Answer' }] }] }] },
result = [before].map(iter);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can achieve this using map, I wrote an simple test to show my point here
this is the important part of the code
function rename(item: any) {
return {
title: item.item,
key: item.id,
color: item.type === 'Question' ? 'red' : 'blue',
items: item.items?.map(rename)
}
}
console.log(items.map(rename))
Of course if you're using typescript, change any to the appropriate type and pay attention that I'm using ? operator which will not work with javascript, so you could do something like
...
items: item.items ? item.items.map(rename) : undefined
...
I am trying to define an interface for the following data:
result =
{
"data1" : [ { "type1" : 30 }, { "type2" :40 } ],
"data1" : [ { "abc" : 40 }, { "def" 940 } ],
"data3" : []
}
here the keys and values inside result object are dynamic. Even the values inside array of objects are dynamic but it will be of format string: number or that array can be empty just as in data3.
I tried using [x:any]: any, but looks like it will remove the significance of rest of the types defined in interface as it will match eveything.
Can someone help me here?
You can define dynamic key interface as follows:
interface Result {
[key: string]: {
[childKey: string]: number;
}[];
}
Something similar you can do -->
You don't need to use an indexer (since it a bit less typesafe). You have two options :
interface EnumServiceItem {
id: int; label: string; key: any
}
interface EnumServiceItems extends Array<EnumServiceItem>{}
// Option A
var result: EnumServiceItem[] = [
{ id: 0, label: 'CId', key: 'contentId' },
{ id: 1, label: 'Modified By', key: 'modifiedBy' },
{ id: 2, label: 'Modified Date', key: 'modified' },
{ id: 3, label: 'Status', key: 'contentStatusId' },
{ id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
{ id: 5, label: 'Title', key: 'title' },
{ id: 6, label: 'Type', key: 'contentTypeId' },
{ id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
];
// Option B
var result: EnumServiceItems = [
{ id: 0, label: 'CId', key: 'contentId' },
{ id: 1, label: 'Modified By', key: 'modifiedBy' },
{ id: 2, label: 'Modified Date', key: 'modified' },
{ id: 3, label: 'Status', key: 'contentStatusId' },
{ id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
{ id: 5, label: 'Title', key: 'title' },
{ id: 6, label: 'Type', key: 'contentTypeId' },
{ id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
]
Personally I recommend Option A (simpler migration when you are using classes not interfaces).
This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 3 years ago.
I want to modify the data that API provides to client. I can only retrieve the unique category value using Set. Then I'm stuck how to proceed further.
const serverData = [
{
category: 'address',
label: 'Street',
type: 'text'
},
{
category: 'address',
label: 'Country',
type: 'text'
},
{
category: 'person',
label: 'FirstName',
type: 'text'
},
{
category: 'person',
label: 'LastName',
type: 'text'
}
];
I want the above to be modified like below. There can be many categories
const modifiedData = {
address : [
{
label: 'Street',
type: 'text'
},
{
label: 'Country',
type: 'text'
},
],
person : [
{
label: 'FirstName',
type: 'text'
},
{
label: 'LastName',
type: 'text'
}
]
};
Please help me achieve this. Thanks in advance!
You could use the reduce function to format your data. Here is an example:
const serverData = [
{
category: 'address',
label: 'Street',
type: 'text'
}, {
category: 'address',
label: 'Country',
type: 'text'
}, {
category: 'person',
label: 'FirstName',
type: 'text'
}, {
category: 'person',
label: 'LastName',
type: 'text'
}
];
const formatData = data => {
return data.reduce((result, item) => ({
...result,
[item.category] : [
...(result[item.category] || []),
item
]
}), {});
}
console.log(formatData(serverData));
I have an object with few items and I want to update the values of one property options from another object.
Object 1 :
structure = [
{
id: 'name',
label: 'Name',
filterType: 'text',
filterOn: 'contains'
},
{
id: 'address',
label: 'Address',
filterType: 'text',
filterOn: 'contains'
},
{
id: 'phone',
label: 'Phone',
filterType: 'select',
filterOn: 'contains',
options: [{ label: 'abc', value: 'abc' },
{ label: 'xyz', value: 'xyz' },
{ label: 'mno', value: 'mno' }]
}
];
if the id is phone then I want to get the values from the object 2 phoneList and assign it to the options instead of hard coding it.
options: [{ label: 'abc', value: 'abc' },
{ label: 'xyz', value: 'xyz' },
{ label: 'mno', value: 'mno' }]
}
];
object 2 is
this.props.phoneList = [{name: 'aaa', age: 11},{name : 'bbb' , age : 12}, and so on
]
label and values will be this.props.phoneList[i].name
how to loop over this and get the latest values from the other object
First use filter to identify the object with id phone. Then use map to transform this.probs.phoneList in the desired format and assign to options.
structure.filter (x => x.id == 'phone')[0].options = this.probs.phoneList.map (x => ({label: x.name, value: x.name}));