I am using this react-select: https://github.com/JedWatson/react-select
The format for options data that they require is:
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry'},
{ value: 'vanilla', label: 'Vanilla' }
];
My array is set up differently as follows:
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
]
I am not able to change my array. If try to use name or value in my option items, I encounter issues using them with select-react. If I change my name to value, the select options are populating, however I don't want to do that.
Can anyone teach me how can I change my array's name to value?
You could use the .map() function to make the data in columns suitable for use with react-select.
The .map() function is available on the Array type. It creates a new array from the array you call it on, and allows you to provide a function that transforms/changes each item as it is copied from the original array.
You can make use of it as follows:
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
]
const options = columns.map(function(row) {
// This function defines the "mapping behaviour". name and title
// data from each "row" from your columns array is mapped to a
// corresponding item in the new "options" array
return { value : row.name, label : row.title }
})
/*
options will now contain this:
[
{ value: 'OrderNumber', label: 'Order Number' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
];
*/
For more information, see the MDN documentation for .map()
If you just want to rename the name property to value you can use a map and destruct the name property as value and pick the rest.
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
];
const newColumns = columns.map( item => {
const { name: value, ...rest } = item;
return { value, ...rest }
}
);
console.log( newColumns );
But, I suspect that you would want this since react-select doesn't work (as far as I see) with title. It waits for a label prop I guess. If this is so, go with and change all the properties as #Dacre Denny suggested. I like arrow functions :) So:
const newColumns = columns.map( item =>
( { value: item.name, label: item.title } )
);
Use destructuring with renaming property will simplify.
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" },
];
const columns = options.map(({ value: name, label: title }) => ({
name,
title,
}));
console.log(columns);
Related
I'm trying to populate a PrimeReact Tree with data from sqlite3 database, but it doesnt work.
Here is my SQL-Query:
select 'prj:'||p.id as key,p.name as label,(
select json_group_array(json_object('key',key,'label',label))
from(
select 'tpr:'||tpr.id as key,tpr.name as label from tpr
where tpr.prjid=p.id
and tpr.active="true"
order by tpr.id
)
) as children
from prj p,usr_right r
where p.id=r.prjid
and p.active="true"
and r.usrid=$1
order by p.id
I get following JSON-Code:
[
{
key: 'prj:1',
label: 'Projekt 1',
children: '[{"key":"tpr:1","label":"Teilprojekt 1"},{"key":"tpr:2","label":"Teilprojekt 2"}]'
},
{ key: 'prj:2', label: 'Projekt 3', children: '[]' },
{ key: 'prj:3', label: 'Projekt 2', children: '[]' }
]
This is OK but i figured out, that the children are not rendered, because there are quotes around the square brackets at the children path - how can i fix this?
If initial is your json to be mapped to Tree, then you need to make a slight modification to convert string to array
let initial = [
{
key: 'prj:1',
label: 'Projekt 1',
children: '[{"key":"tpr:1","label":"Teilprojekt 1"},{"key":"tpr:2","label":"Teilprojekt 2"}]'
},
{ key: 'prj:2', label: 'Projekt 3', children: '[]' },
{ key: 'prj:3', label: 'Projekt 2', children: '[]' }
]
let converted = initial.map(obj => ({ ...obj, children: JSON.parse(obj.children)}))
console.log(converted)
Situation is simple: Make a double map to deconstruct into a single Array rather then multiple.
The Data example:
const data = [
{
name: 'testa',
values: [
{ index: '1993', value: 5 },
{ index: '1994', value: 6 },
],
},
{
name: 'testb',
values: [
{ index: '1991', value: 8 },
{ index: '1992', value: 3 },
{ index: '1993', value: 9 },
],
},
];
A method should take this array and convert into a single array of this data (order dosent matter):
const proccessedData = [
{ index: '1993', value: 5, name: 'testa' },
{ index: '1994', value: 6, name: 'testa' },
{ index: '1991', value: 8, name: 'testb' },
{ index: '1992', value: 3, name: 'testb' },
{ index: '1993', value: 9, name: 'testb' },
];
I achieve this by using this method I created:
const getData = (obj) => {
const data = [];
obj.map(({ values, name }) => {
data.push(...values.map(({ index, value }) => ({ index, value, name })));
});
return data;
};
And it works BUT I disliake it because of (read below in The Problem):
THE PROBLEM
It depends on const data = [] to do a data.push(...). Would prefer that it would auto decontruct it so a method would look something like this:
const getData = (obj) =>
obj.map(({ values, name }) => values.map(({ index, value }) => ({ index, value, name })));
Basically, on a single line, without the use of another variable BUT the return structure would remain as mentioned above. But using thtis method it returns an array with 2 different arrays inside.
It is being used inside another structure like so:
const config = {
data: getData(data),
height: 400,
xField: "index",
yField: "value",
seriesField: "name"
};
So it has to return deconstructed array already without involving any other variables. Yes, I could leave it as it is right now, but I wanna do the deconstruction way as its cleaner, in my opinion, and I would learn something new.
NOTE doing data: {...getData(data)}, or data: [...getData(data)], does Not work.
A working example to play around: https://codesandbox.io/s/bold-cannon-fwot6?file=/src/App.js:690-826
This would be simpler with flatMap:
const data = [
{
name: 'testa',
values: [
{ index: '1993', value: 5 },
{ index: '1994', value: 6 },
],
},
{
name: 'testb',
values: [
{ index: '1991', value: 8 },
{ index: '1992', value: 3 },
{ index: '1993', value: 9 },
],
},
];
proccessedData = data.flatMap(d => d.values.map(v => ({...v, name: d.name})))
console.log(proccessedData)
You can also try this: I am using here map function twice, and then flatten into a single array, The flatMap method is identical to a map followed by a call to a flat of depth 1.
const data = [
{
name: 'testa',
values: [
{ index: '1993', value: 5 },
{ index: '1994', value: 6 },
],
},
{
name: 'testb',
values: [
{ index: '1991', value: 8 },
{ index: '1992', value: 3 },
{ index: '1993', value: 9 },
],
},
];
const dataProcess = data
.map((d) =>
d.values.map((v) => ({...v, name: d.name}))
).flat();
console.log(dataProcess);
I'm "consolling" the entire code... but I can't find any issue, only a weird behaviour.
Let me explain:
I've an angular component (let's call it parent) which send some tags to his child through a inputTags array.
Then I need to set another list with ALL the tags of the user, called allTags.
The array (both inputTags and allTags) is formatted like this:
{ id: 'tagId', name: 'tagName' }
I need to make an unified array of those two. The expected output should contain an array of items that it's formatted like this: { id: 'tagId', name: 'tagName', selected: boolean }
In order to do this I'm mapping the allTags array in this way:
Let's suppose that:
inputTags = [
{ id: 'work', name: 'Work' },
{ id: 'motivation', name: 'Motivation' }
];
allTags = [
{ id: 'network', name: 'Network' },
{ id: 'work', name: 'Work' },
{ id: 'smart', name: 'Smart' },
{ id: 'motivation', name: 'Motivation' }
];
Now... allTags are actually retrived from a server, so my code looks something like this:
this.tagsService.getAll().subscribe(tags => {
this.allTags = tags.map(tag => {
let select = false;
this.inputTags.forEach(inputTag => { select = (inputTag.id === tag.id) })
return {
id: tag.id,
name: tag.name,
selected: select,
};
});
})
This for me seems quite standard, but in fact NO, because instead of getting:
allTags = [
{ id: 'network', name: 'Network', selected: false },
{ id: 'work', name: 'Work', selected: true }, // is selected
{ id: 'smart', name: 'Smart', selected: false },
{ id: 'motivation', name: 'Motivation', selected: true } // is selected
];
I get this:
allTags = [
{ id: 'network', name: 'Network', selected: false },
{ id: 'work', name: 'Work', selected: false }, // is NOT selected
{ id: 'smart', name: 'Smart', selected: false },
{ id: 'motivation', name: 'Motivation', selected: true } // is selected
];
Basically the issue is that it's selecting only one tag, not multiple tags.
You can try some:
this.allTags = tags.map(tag => {
return {
id: tag.id,
name: tag.name,
selected: this.inputTags.some(inputTag => inputTag.id === tag.id)
};
});
JavaScript Array map() Method
*)creates a new array with the results of calling a function for every array element and it calls the provided function once for each element in an array, in order.
Note: map() Method does not execute the function for array elements without values and it does not change the original array.
Try the following:
this.allTags = allTags.map(tag => ({
id: tag.id,
name: tag.name,
selected: inputTags.some(i => i.id === tag.id),
}))
I have the following array of object
const skus = [
{
id: 1,
features: ["Slim"],
fields: [
{ label: "Material", value: "Material1" },
{ label: "Type", value: "Type1" }
]
},
{
id: 2,
features: ["Cotton"],
fields: [
{ label: "Material", value: "Material2" },
{ label: "Type", value: "Type2" }
]
},
{
id: 3,
features: ["Slim"],
fields: [
{ label: "Material", value: "Material3" },
{ label: "Type", value: "Type1" }
]
}
]
And i want the expected output to be
const output = [
{ label: "features", value: ["Slim", "Cotton"] },
{ label: "Material", value: ["Material1", "Material2", "Material3"] },
{ label: "Type", value: ["Type1", "Type2"] }
]
I tried the following way
const output = [];
let featureArr = [];
let fieldsArr = []
skus.forEach(e => {
e.features.forEach(f => {
featureArr.push(f);
});
e.fields.forEach(f => {
fieldsArr.push({ label: f.label, value: f.value });
});
});
featureArr = _.uniq(featureArr);
fieldsArr = _.uniqBy(fieldsArr, 'value')
fieldsArr = _.groupBy(fieldsArr, 'label');
output.push({ label: 'Features', value: featureArr })
for (const k in fieldsArr) {
let valArr = []
valArr = fieldsArr[k].map(v => v.value)
output.push({ label: k, value: valArr });
}
I'm getting the expected output, but here multiple loops are present. Is there a way on how can i write the solution in more optimized way.
You could take a grouping function for nested properties, where a map, an array for iterating, group and value keys are handed over. The result is a map with all collected values for each group.
Later get all unique values from the map and build a new array of objects.
const
skus = [{ id: 1, features: ["Slim"], fields: [{ label: "Material", value: "Material1" }, { label: "Type", value: "Type1" }] }, { id: 2, features: ["Cotton"], fields: [{ label: "Material", value: "Material2" }, { label: "Type", value: "Type2" }] }, { id: 3, features: ["Slim"], fields: [{ label: "Material", value: "Material3" }, { label: "Type", value: "Type1" }] }],
getGrouped = (map, array, key, value) => array.reduce((m, o) =>
m.set(o[key], [...(m.get(o[key]) || []), o[value]]), map),
result = Array.from(
skus.reduce((m, o) =>
getGrouped(
m.set('features', [...(m.get('features') || []), ...o.features]),
o.fields,
'label',
'value'
),
new Map
),
([label, value]) => ({ label, value: [...new Set(value)] })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
First Build an object with values as Sets. Then convert the object of sets into array of array.
const skus = [
{
id: 1,
features: ["Slim"],
fields: [
{ label: "Material", value: "Material1" },
{ label: "Type", value: "Type1" }
]
},
{
id: 2,
features: ["Cotton"],
fields: [
{ label: "Material", value: "Material2" },
{ label: "Type", value: "Type2" }
]
},
{
id: 3,
features: ["Slim"],
fields: [
{ label: "Material", value: "Material3" },
{ label: "Type", value: "Type1" }
]
}
];
const update = data => {
const res = {};
data.forEach(item => {
const features = res["features"] || new Set();
item.features.forEach(fea => features.add(fea));
res["features"] = features;
item.fields.forEach(field => {
const labels = res[field.label] || new Set();
labels.add(field.value);
res[field.label] = labels;
});
});
return Object.keys(res).map(key => ({ label: key, value: [...res[key]] }));
};
console.log(update(skus));
If you can use them, Sets will be your friend here:
//data
const skus = [{id: 1,features: ["Slim"],fields: [{ label: "Material", value: "Material1" },{ label: "Type", value: "Type1" }]},{id: 2,features: ["Cotton"],fields: [{ label: "Material", value: "Material2" },{ label: "Type", value: "Type2" }]},{id: 3,features: ["Slim"],fields: [{ label: "Material", value: "Material3" },{ label: "Type", value: "Type1" }]}];
//solution
const output = Object.entries(skus.reduce((map,sku) => {
sku.features.forEach(feat => map.features.add(feat));
sku.fields.forEach(field => (map[field.label] = (map[field.label] || new Set()).add(field.value)));
return map;
}, {features: new Set()})).map(([label, set]) => ({label, value: Array.from(set)}));
//display
console.log(output);
Each feature array and field array only get iterated exactly once using this approach.
If you can't use Sets, you can emulate their behavior using js objects. The goal is to use some structure that doesn't need to be iterated again to find unique values.
The following function will do the job
const fn = (array) => {
return array.reduce((result, element) => {
const features = result[0].value
const feature = element.features[0]
if (!features.includes(feature)) {
features.push(feature)
}
const materials = result[1].value
const material = element.fields[0].value
if (!materials.includes(material)) {
materials.push(material)
}
const types = result[2].value
const type = element.fields[1].value
if (!types.includes(type)) {
types.push(type)
}
return result
}, [
{ label: 'features', value: [] },
{ label: 'Material', value: [] },
{ label: 'Type', value: [] }
])
}
BUT, your object structure is quite messy, you should likely build accessor functions that extract information from your initial elements, and use some helper functions to populate your result object.
Anyway, read more about the 'reduce' function used here ;)
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce
I'm trying to get a country label (name) from a value (country code) in an object.
In Vue.js I'm trying to build a computed property to return the name of the country based on the country code from an API request.
In the template:
countryLabel () {
var countries = require('../../plugins/countries')
var countryCode = this.content.country
function getLabelByValue(countries, countryCode) {
return Object.keys(countries).find(label => countries[value] === countryCode)
}
}
From a list of countries:
module.exports = [
{ value: 'AF', label: 'Afghanistan' },
{ value: 'AX', label: 'Aland Islands' },
{ value: 'AL', label: 'Albania' },
{ value: 'DZ', label: 'Algeria' },
{ value: 'AS', label: 'American Samoa' },
{ value: 'AD', label: 'Andorra' },
{ value: 'AO', label: 'Angola' },
{ value: 'AI', label: 'Anguilla' },
{ value: 'AQ', label: 'Antarctica' },
{ value: 'AG', label: 'Antigua and Barbuda' },
...
]
You probably don't want to be calling Object.keys on an array.
Something like this is probably more what you want:
function getLabelByValue(countries, countryCode) {
const entry = countries.find(item => item.value === countryCode);
return entry ? entry.label : null;
}
The problem is that calling Object.keys on an array will return an array of numbers that have been converted to strings:
> console.log(Object.keys(['this', 'is', 'an', 'array']));
['0', '1', '2', '3']
Since your exports is already an array, you can call find() on it directly.
A better way to do this would be to use an object, which is always the fastest way to lookup anything in javascript because objects are dictionaries. So if you changed your export to look like:
{
AF: 'Afghanistan',
AX: 'Aland Islands',
etc...
}
then you'd be able to do instant lookups by doing countries[countryCode].
Based on rossipedia's answer this is working for me:
countryLabel () {
const countries = require('../../plugins/countries')
return countries.find(item => item.value === this.content.country).label
}