how to push the data from a select in a single array? - javascript

I'm using react-select, my api expects that i send an array of strings like this ["purple", "red", "orange"] but react-select gives me an array of objects, so what I did was map throught newValue picking each value and putting in an vaiable array, but i'm getting each value in separated arrays like this ["purple"], ["red"], ["orange"]
handleChange = (newValue: any, actionMeta: any) => {
console.log("newValue-->",newValue);
newValue.map((obj: any) => {
const array = [];
array.push(obj.value);
console.log("array-->",array);
});
complete code:
https://codesandbox.io/s/react-codesandboxer-example-sf7tz?file=/example.js

Initialize your array outside before map.
Otherwise you are creating new array for each object.
const array = [];
newValue.map((obj: any) => {
array.push(obj.value);
console.log("array-->",array);
});

As per the react select docs, it should be an array of objects with value and label. so in your case you can do in the below way.
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
let input = ["purple", "red", "orange"]
let output = input.map(item => ({value: item, label: capitalizeFirstLetter(item) }))
console.log(output)
Explanation on the Question snippet
newValue.map((obj: any) => {
const array = [];
array.push(obj.value);
console.log("array-->",array);
});
Here you are mapping through each object, then every time mapping you are creating an empty array, to that array you push the value and print it.
So take first item as example, red iterates -> empty array created -> push the red value to empty array and then printing it.
So this loops three times since the length of the array is 3, so three times you get the array.
Fix on the question snippet is declare the array outside the loop and push in the same manner as the doc suggest then you can pass to react select component as options props and it will work as expected.

Related

JavaScript Objects filtering out specific property names

I am creating a filter for a diagram. Whenever a filter is clicked it should remove that category from the diagram. The api call returns an object with names. let’s say the object returns 40 items and I want to filter 5 out by name. What is the best way to approach this?.
I tried to manually type the property names into an array and run the .filter on my object like below. However it returns the entire object unfiltered.
filterDiagram() {
Const array = [“all the names of the properties I want to filter out”]
carbonates = array.forEach(x) => {console.log(x)}
Const filterCat = data.filter (io =>
io.name !== carbonates)
}
Let's say, the array consists of all the names/categories you want to take out.
const toBetakenOut = ['fruits','salts', 'etc' ]
// Please make sure they are not 1 string but rather comma-separated values.
You can filter the API data by using the filter function on the data,to remove objects with names that are within toBetakenOut.
const filterCat = data.filter (io => !toBetakenOut.includes(io.name))
function filterDiagram(){
const dontWantsArray = [/*all of the things you dont want*/];
// Outputs an array of keys
const filteredKeys = Object.keys(yourJSObject)
.filter(key => !dontWantsArray.includes(key));
// After you found the keys you can get the values to another array by keys
const filteredValues = filteredKeys.map(key => yourJSObject[key]);
}

How to add and update objects into array of objects?

I am trying to dynamically add an object to an array of objects, I have been trying to Destructuring the main object but it adds a number to the end of the parent array. This is what I have:
const [data, setData] = useState ([
{
_id:1,
firstName:'Leo',
lastName:'Miller',
telephone:'+569273829',
mail:'leo.miller#gmail.com',
work:[
{_id:1, startWorkDate:'01/01/2015', endWorkDate:'01/02/2017', work:'description...'},
{_id:2, startWorkDate:'01/01/2018', endWorkDate:'01/02/2020', work:'description...'}
]
}];
I generate dynamically this object:
const value = {_id:3, startWorkDate:'01/01/2018', endWorkDate:'01/02/2020', work:'description...'}
I need to add it into data.work and after that update only the description of work._id[3]
I try with this function
const addNewWork = (value) => {
let copyData = [...data, data[0].workExperience.push(value)]
return setData(copyData)
}
but for some reason doesn't add correctly the object. Help please!
You have an array and not an object. Your statement
let copyData = [...data, data[0].workExperience.push(value)]
is doing two things:
mutating the state by doing push(). Which is not the react way.
creating a new array. Also adding a new item to the array, but that is the new length of data[0].workExperience.
The return value of Array.prototoype.push is:
The new length property of the object upon which the method was called.
What you have to do is:
Make a copy of the array. Can use ... (spread operator) here.
Make a copy of the array object you want (first index). Try to add the object to its specific property workExperience.
const addNewWork = (value) => {
let newData = [...data];
let newWorkExperienceArray =
[...data[0].workExperience,value];
let newDataFirstObject = {...data[0], workExperience : newWorkExperienceArray};
newData[0] = newDataFirstObject;
return setData(newData)
}
You can also update the property. I didn't find the relevant code in your question as to what I have to update so I didn't update anything in the third workExperience object.
EDIT: It seems in your code the property name is work and not workExperience. Please confirm. The above code uses workExperience, you can replace it by work if that is the case
You can do this with this simple function:
const addNewWork = (value) => {
let updatedObj = data[0];
updatedObj.work.push(value)
// updates your object each time
let copyData = [updatedObj]
// adds a new object for each call
// let copyData = [...data, updatedObj]
return setData(copyData)
}
Now it updates the object in your state. If you want to add a new object for each call just uncomment let copyData = [...data, updatedObj] and comment out let copyData = [updatedObj]
When you set state for array your setter is a quite bite different
setData(prevData => [...prevData, newItem]) // to add a single item to array
setData(prevData => newArray) // to replace entire array

How can I add the objects in multiple arrays along their index

I have an array of objects
[
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}]
]
That I need to reduce to [{data:3},{data:6},{data:9}] via addition.
Objects of index 0 are added, objects of index 1 are added, and objects of index 2 are added.
Is there a Javascript function like reduce that can manage this?
The previous answer is good but it only works if your arrays are always the same size.
For example, having this initial input would break the code:
[
[{data:1},{data:2},{data:3}, {data:4}],
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}]
]
To fix that you could add a check inside the reducer, to make sure the next array has an object at that index.
Another problem is if you have this initial input:
[
[{data:1},{data:2},{data:3}, {data:4}],
[{data:1},{data:2},{data:3}, {data:4}, {data:5}],
[{data:1},{data:2},{data:3}]
]
The last object in the second array would be ignored because the initial reducer only takes into consideration the length of the first array.
To handle those exceptions, you could use this refactored code (based on #mickl answer):
// Initial input with different format
const initialInput = [
[{data:1},{data:2},{data:3}, {data:4}],
[{data:1},{data:2},{data:3}, {data:4}, {data:5}],
[{data:1},{data:2},{data:3}]
];
// Sort and reverse to get the array with most items first
const sortedInput = initialInput.sort().reverse();
// Finally use the refactored reducer
const result = sortedInput.reduce((arr,cur) => {
return arr.map((val, i) => {
// This "if" checks if the next array has an item on the same index of previous array
// Which is not the case, for example, from the second to the third item
if (cur[i] && cur[i].data) {
return { data: val.data + cur[i].data }
} else {
return { data: val.data}
}
})
});
console.log(result)
You can use array.reduce to aggregate the data across multiple arrays and array.map to sum up the values since it takes an arrow function where second parameter represents an index of currently processed element:
let input = [
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}]
];
let result = input.reduce((arr,cur) =>
arr.map((val, i) => ({ data: val.data + cur[i].data })));
console.log(result);

How to filter the array of object by matching all values instead of one

I am implementing a filter. it works fine. the problem is it's just matching a single object value instead of all value matching.
Matching means here is, let it be contain any single letter in the value
example: here is my object
{name:"D",color:"Green",size:50}
in case if i pass the filter object as :
let filter1 = {color:"Blu",size:'50'};
at present I am getting single result by matching size. But the color is not matching at all. so the result should be empty.
How to mach all values in the object and get the filtered value.
Live Demo
Code :
const nestedFilter = (targetArray, filters) => targetArray.filter(o => Object.keys(filters).find(k => filters[k].includes(o[k])));
let products = [
{name:"A",color:"Blue",size:70},
{name:"B",color:"Blue",size:60},
{name:"C",color:"Black",size:70},
{name:"D",color:"Green",size:50}
];
let filter1 = {color:"Blu",size:'50'};
console.log(nestedFilter(products, filter1));
Replace the .find invocation with .every. Be aware though that by using includes you expect your property values to be String.
If you want includes to work to other way round, so that the filter value can be a substring of the data, you should do:
const nestedFilter = (targetArray, filters) =>
targetArray.filter(o => Object.keys(filters).every(k =>
String(o[k]).includes(filters[k]))
)
)
The o[k] value needs to be converted to string, as otherwise you cannot apply includes to it (cf. size which is a number)
Check whether every of the Object.entries of the filter passed is equal to the same entry on the object being iterated over. If you want partial matches and are using different types of variables, it sounds like you also need to coerce them to strings first, so you can use .includes.
const nestedFilter = (targetArray, filters) => targetArray.filter(
obj => Object.entries(filters).every(
([key, val]) => String(obj[key]).includes(val)
)
);
let products = [
{name:"A",color:"Blue",size:70},
{name:"B",color:"Blue",size:60},
{name:"C",color:"Black",size:70},
{name:"D",color:"Green",size:50},
{name:"E",color:"Blu",size:'50'}
];
let filter1 = {color:"Blu",size:'70'};
console.log(nestedFilter(products, filter1));

.map() not a function within reduce()

I have the following code:
map(res => {
const finalRows = res.reduce((acc, curr) => {
return [
...acc,
...curr.map(row => ({
...row,
chevron: ' ',
}))
]
}, []);
.....
'res' looks like an array of objects, those objects being rows. Using reduce(), it should return an array, but I am using map to go through each of the current rows and adding a 'chevron' column. I feel like maybe it doesn't know it's returning an array yet and treating it like an object still, therefore I'm getting the error 'curr.map not a function', however, I'm not sure if that is the real issue. Any ideas?
Let's take a deeper look at your code:
As you said, res is an array of objects
The second argument of .reduce's callback is the current item in the provided array
So curr is an item of res
But here, it seems that curr isn't an array but instead another type of object (like JSON), which is why you're getting this error.
It would only have worked if res had been an array of arrays, as .map cannot be called on non-array objects.
Also, another way of writing your code in a more simple way is:
// For each row of the `res` array...
res.map(row => {
// Clone it, so the new row isn't linked to the existing one
const newRow = row.slice(0);
// Set its 'chevron' property
newRow.chevron = ' ';
// Return the new row
return newRow;
}); // Here we get the new array of objects

Categories

Resources