Remove n number of elements from object - reactjs

i have a object like
obj = {name:"xxx" , des1:"x",des2:"xx",des3:"xxx" , age:"12"}.
But the property of des can be incresed as des1,des2,des3,des4 ... according to the users inputs. So basically we don't know how much of "des" properties are there in the object.
I want do something like this. Grab all the properties of des and put them in array. Then update the object as follows
obj = {name:"xxx" , description:["x","xx","xxx"] , age:"12"}
how can I achieve this using ES6 syntax

you can transform your data in this way:
const transformed = Object.keys(obj).reduce(
(acc, key) => {
return key === 'name' || key === 'age'
? { ...acc, [key]: obj[key] }
: { ...acc, description: [...acc.description, obj[key]] }
},
{ description: [] }
)

What about this one?
const f = {name:"xxx", des1:"x", des2:"xx", des3:"xxx", age:"12"};
const { name, age, ...rest} = f;
const result = { name, age, description: Object.values(rest) };
console.log(result) // { name: 'xxx', age: '12', description: [ 'x', 'xx', 'xxx' ] }

You can make use of reduce and then match the string with the regex which checks if the string is des, followed by a number
var obj = {name:"xxx" , des1:"x",des2:"xx",des3:"xxx" , age:"12"}
const res = Object.keys(obj).reduce((acc, key)=> {
if(key.match(/^des([0-9]+)$/)) {
if(acc.description) {
acc.description.push(obj[key]);
} else {
acc.description = [obj[key]];
}
} else {
acc[key] = obj[key];
}
return acc;
}, {})
console.log(res);

Related

Filtering array by input value react

I have a little problem with filtering my array.
I want display a product filtered by input value with a name or platform or something other value. With name is no problem, but i don't know how to do it with platforms.
Bottom is my logic and file with products, txh very much for help
live: live
repo: repo
const [inputText, setInputText] = useState('')
const inputHandler = e => {
const text = e.target.value.toLowerCase()
setInputText(text)
}
const filteredData = PRODUCT_LIST.filter(el => {
if (inputText === '') {
return
} else {
return el.name.toLowerCase().includes(inputText)
}
})
const PRODUCT_LIST = [
{
id: 'gow',
name: 'God of War',
developer: 'Santa Monica Studio',
category: 'games',
platform: 'PlayStation 4',
version: 'PL',
price: 39,
},]
You need to make a conditional check.
First, check whether the search text matches the name; if it fits, return the list. If not, then check whether it matches the platform.
const filteredData = PRODUCT_LIST.filter(el => {
const findByName = el?.name?.toLowerCase().includes(inputText);
const findByPlatform = el?.platform?.toLowerCase().includes(inputText);
if (inputText === '') {
return
} else {
return findByName || findByPlatform
}
})
You should do something like this just return true when you are getting empty string. Let me know if it works.
const filteredData = PRODUCT_LIST.filter(el => {
if (inputText === '') {
return true;
} else {
return (el.name.toLowerCase().includes(inputText.toLowerCase()) || el.platform.toLowerCase().includes(inputText.toLowerCase()))
}
})

Generic filter for X number of properties

I want to make a generic filter function. Currently I have a function that looks like this:
const filterRows = () => {
items.filter((item) => {
if(selectedDrinks.length > 0 && selectIds.length > 0) {
return selectedDrinks.includes(item.description) && selectedIds.includes(item.props.id)
}else if(selectedDrinks.length > 0) {
return selectedDrinks.includes(item.description)
}else if(selectedIds.length > 0) {
return selectedIds.includes(item.props.id)
}
}
}
The number of if checks I need to do will grow exponentially if I add one more thing to filter by.
I've made a pathetic try below. One issue I encountered is if I have a nested structure and want to access ["props/id"] as I don't know the syntax for it. Also tried ["props:id"] etc. And if I add multiple strings in the query it does not work either. And even if I could add multiple strings properly it would only work as an OR.
And for me it would be selectedDrinks && selectedId as both need to match for it to filter, not selectedDrinks || selectedIds
I want to include everything in both selectedDrinks and selectedIds as a query, and they should filter only if both are included in "assets" as description and props:id. I should also be able to add e.g "selectedNames" as a third "query parameter".
const selectedDrinks: string[] = [
"cola",
"fanta",
]
const selectedIds : string[] = [
"5",
"4",
]
interface s {
description: string;
name: string;
props: {
id: string
}
}
const items: s[] = [
{
description: "cola",
name: "computer",
props: {
id: "4"
}
},
{
description: "fanta",
name: "laptop",
props: {
id: "5"
}
},
{
description: "sprite",
name: "phone",
props: {
id: "6"
}
}
]
export function genericFilter<T>(
object: T,
filters: Array<keyof T>,
query: string[]
):boolean {
if(query.length === 0)
return true
return filters.some(filter => {
const value = object[filter]
console.log(value)
if(typeof value === "string") {
return value.toLowerCase().includes(query.map(q => q.toLowerCase()).join(""))
}
if(typeof value === "number") {
return value.toString().includes(query.map(q => q.toLowerCase()).join(""))
}
return false
})
}
const myFilterResult = items.filter((asset) => genericFilter(item, ["props", "name"], ["5"]))
console.log(myFilterResult)
If anyone is interested, here is how I solved it.
/**
*
* #returns A new list of filtered objects
* #param objects The objects that we want to filter
* #param properties The properties we want to apply on the object and compare with the query
* #param queries The queries we want to filter by
*/
export function genericFilter<T>(
objects: T[],
properties: Array<keyof T>,
queries: Array<string>[] | Array<number>[]
):T[] {
return objects.filter((object) => {
var count = 0;
properties.some((props) => {
const objectValue = object[props]
if(typeof objectValue === "string" || typeof objectValue === "number") {
queries.forEach((query) => {
query.forEach((queryValue) => {
if(queryValue === objectValue) {
count+=1;
}
})
})
}
})
return count === properties.length;
})
}
export default genericFilter;
How you call the function, can include X amount of filters and strings to search for.
const result = genericFilter(assets, ["description", "id", "name"], [selectedAssetTypes, selectedIds, selectedNames])

REACT UPDATE A DATA

I have a problem trying to update an Array of Objects that lives in a Themecontext, my problem is with mutation, I'm using Update from Immutability helpers. the thing is that when I update my array in my specific element, This appears at the end of my object.
This is my code:
function changeValueOfReference(id, ref, newValue) {
const namevalue = ref === 'colors.primary' ? newValue : '#';
console.warn(id);
const data = editor;
const commentIndex = data.findIndex(function(c) {
return c.id === id;
});
const updatedComment = update(data[commentIndex], {styles: { value: {$set: namevalue} } })
var newData = update(data, {
$splice: [[commentIndex, 1, updatedComment]]
});
setEditor(newData);
this is my result:
NOTE: before I tried to implement the following code, but this mutates the final array and break down my test:
setEditor( prevState => (
prevState.map( propStyle => propStyle.styles.map( eachItem => eachItem.ref === ref ? {...eachItem, value: namevalue}: eachItem ))
))
Well, I finally understood the issue:
1 - commentIndex always referenced to 0
The solution that worked fine for me:
1 - Find the index for the Parent
2 - Find the index for the child
3 - Add an array []
styles : { value: {$set: namevalue} } => styles :[ { value: [{$set: namevalue}] } ]
Any other approach is Wellcome
Complete Code :
function changeValueOfReference(id, referenceName, newValue) {
const data = [...editor];
const elemIndex = data.findIndex((res) => res.id === id);
const indexItems = data
.filter((res) => res.id === id)
.map((re) => re.styles.findIndex((fil) => fil.ref === referenceName));
const updateItem = update(data[elemIndex], {
styles: {
[indexItems]: {
value: { $set: namevalue },
variableref: { $set: [''] },
},
},
});
const newData = update(data, {
$splice: [[elemIndex, 1, updateItem]],
});
setEditor(newData);
}

How to convert a tree into an array?

I have a tree object which is an irregular tree which children's names and key values can change everytime I run my code. For example:
{
addressRouter: 192.168.0.1,
addresses:
{
address1: 'A',
},
{
address2: 'B',
},
{
ports: [
{
portA: 'C',
portB: null
},
}
route: 'D',
}
so the names: 'addressRouter', 'addresses', 'address1', etc and their keys are unpredictable but I need to convert the tree object in arrays with the following format:
addressRouter
addresses/address1
addresses/address2
addresses/ports/portA
addresses/ports/portB
route
and then have their keys next to them.
I have this function to construct the tree, which is correct:
const iterate = (obj, obj2) => {
Object.keys(obj).forEach(key => {
obj2[key] = obj[key];
if (typeof obj[key] === 'object') {
iterate(obj[key], obj2)
}
})
}
but after debugging, I realized it doesn't get all branches.
We can use a recursive function to traverse the tree and get the keys in the required format.
I am assuming addresses in the given tree object is an array of objects
function processTree(obj, rootKey) {
const arr = [];
obj && Object.keys(obj).forEach(key => {
const val = obj[key];
if (val && val instanceof Array) {
val.forEach(item => arr.push(...processTree(item, key)))
}else if (val && typeof(val) == "object") {
arr.push(...processTree(val, key));
}else {
arr.push(key);
}
});
return rootKey ? arr.map(item => rootKey + "/" + item) : arr;
}
console.log(processTree(tree, null));
Result : ["addressRouter", "addresses/address1", "addresses/address2", "addresses/ports/portA", "addresses/ports/portB", "route"]
I just write the code below, see if it's what you want.
const tree = {
addressRouter: '192.168.0.1',
addresses: [
{
address1: 'A',
},
{
address2: 'B',
},
{
ports: [
{
portA: 'C',
portB: null,
},
],
},
],
route: 'D',
};
const traverse = (input) => {
const resultList = [];
const isEndPoint = (obj) => {
return typeof obj !== 'object' || obj === null;
};
const buildPath = (currentPath, key) =>
currentPath === '' ? key : `${currentPath}/${key}`;
const innerTraverse = (tree, currentPath = '') => {
if (tree !== null && typeof tree === 'object') {
Object.entries(tree).forEach(([key, value]) => {
if (isEndPoint(value)) {
resultList.push(buildPath(currentPath, key));
return;
}
let path = currentPath;
if (!Array.isArray(tree)) {
path = buildPath(currentPath, key);
}
innerTraverse(value, path);
});
}
};
innerTraverse(input);
return resultList;
};
console.log(traverse(tree));
/**
* [
* 'addressRouter',
* 'addresses/address1',
* 'addresses/address2',
* 'addresses/ports/portA',
* 'addresses/ports/portB',
* 'route'
* ]
*/
I've just found the loop I needed it here, which is:
function* traverse(o,path=[]) {
for (var i of Object.keys(o)) {
const itemPath = path.concat(i);
yield [i,o[i],itemPath];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i],itemPath);
}
}
}
Then, if the tree object (first gray box in my question) were name, for instance, "params", I would do this:
if (params != null && params != undefined) {
for(var [key, value, path] of traverse(params)) {
// do something here with each key and value
if (typeof value == 'string'){
var tempName = '';
for (name in path) {
//console.log(path[name])
p= tempName += path[name] + "/"
}
console.log(p, value)
}
}
}

typescript Promise - persist change in mapped array of objects

I am trying to replace the value (file paths) of the key/value entries in an array of objects upon the if-condition, that a file/ or files exist in the file directory Documents ( ios capacitor ionic ); else, just return the array unchanged.
Arrays
const currentItems = this.data;
const filenames = [val, val, ...];
// for loop
for (let filename of filenames) {
// capacitor FileSystem API; promise
Plugins.Filesystem.stat({
path:filename+'.jpeg',
directory: FilesystemDirectory.Documents
}).then((result) => {
// return path to file in Documents directory ( simplified)
const result.uri = this.imagepath;
// map array
const newItems = this.currentItems.map(e => {
// if entries match set the value for key 'linethree'
if (e.lineone === filename) {
return {
...e,
linethree: this.imagepath
}
}
// else, return e unchanged
else
return { ...e,}
});
}).catch( reason => {
console.error( 'onRejected : ' + reason );
})
}
The problem:
on every iteration - filename of filenames - the original array is mapped again - with its original values; thus each iteration overwrites the change from the previous iteration.
How can it be achieved that the value entry at key 'linethree' for each match - e.lineone === filename - persists ?
Desired replacement:
const filenames = ["uncle"];
[{"lineone":"nagybácsi","linetwo":"uncle","linethree":"./assets/imgs/logo.png"}]
[{"lineone":"nagybácsi","linetwo":"uncle","linethree":"_capacitor_/var/mobile/Containers/Data/Application/D95D4DEF-A933-43F1-8507-4258475E1414/Documents/nagybácsi.jpeg"}]
If i understand well you need something like this:
Solution with Array#Filter, Array#Some and Array#Map
const wantedImagePath = '_capacitor_/var/mobile/Containers/Data/Application/D95D4DEF-A933-43F1-8507-4258475E1414/Documents/nagybácsi.jpeg';
const fileNames = ["uncle"];
const someData = [
{
"lineone":"ikertestvérek; ikrek",
"linetwo":"twins",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone":"nagybácsi",
"linetwo":"uncle",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone":"nőtlen (man)",
"linetwo":"unmarried",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone": "bar",
"linetwo": "foo",
"linethree": "./some/demo/path/logo.png"
}
];
const modifed = someData.filter(x => fileNames.some(y => y === x.linetwo)).map(z => ({ ...z, linethree: wantedImagePath }));
console.log(modifed)
Update:
Solution if you want to keep current data and modify matched:
const wantedImagePath = '_capacitor_/var/mobile/Containers/Data/Application/D95D4DEF-A933-43F1-8507-4258475E1414/Documents/nagybácsi.jpeg';
const fileNames = ["uncle"];
const someData = [
{
"lineone":"ikertestvérek; ikrek",
"linetwo":"twins",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone":"nagybácsi",
"linetwo":"uncle",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone":"nőtlen (man)",
"linetwo":"unmarried",
"linethree":"./assets/imgs/logo.png"
},
{
"lineone": "bar",
"linetwo": "foo",
"linethree": "./some/demo/path/logo.png"
}
];
const modified = someData.map(x => {
let match = fileNames.find(y => x.linetwo === y);
return match !== undefined ? ({ ...x, linethree: wantedImagePath }) : x;
});
console.log(modified)

Resources