Delete specific object with id - javascript

I have an array of objects, I need to delete a complete object based on the id
Input :
filters: [
{
key: "status",
label: "En attente",
value: "waiting",
id: 0
},
{
key: "dateDue[min]",
label: "15/12/2019",
value: "15/12/2019",
id: 1
},
{
key: "dateDue[max]",
label: "02/02/2020",
value: "02/02/2020",
id: 2
},
{
key: "bien",
values: [
{
label: "Studio Bordeaux",
value: 36,
id: 3
},
{
label: "Studio 2",
value: 34,
id: 184
}
]
},
{
key: "type",
values: [
{
type: "receipts",
label: "Loyer",
value: "loyer",
id: 4
},
{
type: "receipts",
label: "APL",
value: "apl",
id: 5
},
{
type: "spending",
label: "taxes",
value: "taxes",
id: 6
}
]
}
]
So I created a removeItem method with the id that must be deleted in parameters
removeItem method :
removeItem = (e, id) => {
const { filters } = this.state;
const remove = _.reject(filters, el => {
if (!_.isEmpty(el.values)) {
return el.values.find(o => o.id === id);
}
if (_.isEmpty(el.values)) {
return el.id === id;
}
});
this.setState({
filters: remove
});
};
I use lodash to make my job easier and more specifically _.reject
My issue is the following :
I manage to correctly delete the classic objects for example
{
key: "status",
label: "En attente",
value: "waiting",
id: 0
}
but my method however does not work for objects of the following form
{
key: "bien",
values: [
{
label: "Studio Bordeaux",
value: 36,
id: 3
},
{
label: "Studio 2",
value: 34,
id: 184
}
]
},
currently the whole object is deleted and not only the object in the values array according to its id
Here is my codesandbox!
thank you in advance for your help
EDIT
I found a solution with lodash (compact), I share my solution here :
removeIdFromCollection = id => {
const { filters } = this.state;
const newFilters = [];
_.map(filters, filter => {
if (filter.values) {
const valuesTmp = _.compact(
_.map(filter.values, value => {
if (value.id !== id) return value;
})
);
if (!_.isEmpty(valuesTmp)) {
return newFilters.push({
key: filter.key,
values: valuesTmp
});
}
}
if (filter.id && filter.id !== id) return newFilters.push(filter);
});
return newFilters;
};
removeItem = id => e =>
this.setState({
filters: this.removeIdFromCollection(id)
});
The values false, null, 0, "", undefined, and NaN are removed with lodash compact (_.compact(array))
Here is my updated codesandbox

You will need to filter the filters array and each values separately. Below is a recursive function which will remove items with the given id from the filters array and from the values property.
PS. This example is not using Lodash as I think it is not needed in this case.
removeIdFromCollection = (collection, id) => {
return collection.filter(datum => {
if (Array.isArray(datum.values)) {
datum.values = this.removeIdFromCollection(datum.values, id);
}
return datum.id !== id;
});
}
removeItem = (e, id) => {
const { filters } = this.state;
this.setState({
filters: this.removeIdFromCollection(filters, id),
});
};

The problem would be the structure of the object. You'll need to refactor for that inconvenient array out of nowhere for uniformity:
// Example
filters: [
...
{
key: "type",
values: [
{
type: "receipts",
label: "Loyer",
value: "loyer",
id: 4
},
...
]
...
}
// could be
filters: [
...
{
key: "type-receipts",
label: "Loyer",
value: "loyer",
id: 4
}
...
]
Repeat the pattern on all of it so you could just use the native array filter like this:
const newFilters = filters.filter(v => v.id !== id);
this.setState({
filters: newFilters,
});

I found a solution with lodash, I share it with you here :
removeIdFromCollection = id => {
const { filters } = this.state;
const newFilters = [];
_.map(filters, filter => {
if (filter.values) {
const valuesTmp = _.compact(
_.map(filter.values, value => {
if (value.id !== id) return value;
})
);
if (!_.isEmpty(valuesTmp)) {
return newFilters.push({
key: filter.key,
values: valuesTmp
});
}
}
if (filter.id && filter.id !== id) return newFilters.push(filter);
});
return newFilters;
};
removeItem = id => e =>
this.setState({
filters: this.removeIdFromCollection(id)
});
Here is my updated codesandbox

Related

How to change multiple Boolean values()Parent Item, Child Item) in an array on click

I am working in a task where I need to change the Boolean values onclick from an array of items, I need to change the Boolean value from array and child array. I have changed the value from an array it's working as expected but inside that array I am having an another array of objects from that I need to change the boolean value. OnClick I need to make parent isProcessing and child isProcessing false. I have tried changing it but I am not getting the expected output , can anyone guide me how to achieve this thanks in advance.
Mock Data:
const mockItems = [
{
id: '1',
itemType: 'metal',
doneBy: {
id: '1',
display: 'Item Name',
},
catg: 'A',
createdDate: '01/01/2021',
updatedBy: {
id: '1',
type: 'M-A',
},
isProcessing: 'true',
subItems: [
{
id: '1',
doneBy: {
id: '1',
display: 'sub item name',
},
status: {
type: 'notapproved',
},
isProcessing: 'true',
},
],
},
];
Code for accessing parent : isProcessing //it's working
const [processingItem, setProcessingItem] = useState(mockItems);
const handleToggle = () => {
setProcessingItem((prevState) =>
prevState.map((prItem, i) =>
i === 0 ? { ...prItem, isProcessing: false } : prItem
)
);
};
//code to change child array Boolean not working
const handleToggle = () => {
setProcessingItem((prevState) => {
prevState.map((prItem, index) => {
if (index === 0) {
const obj = { ...prItem.subItems, isProcessing: false };
return { ...prItem, isProcessing: false, obj };
}
});
});
};
Try this
const handleToggle = () => {
setProcessingItem((prevState) => {
prevState.map((prItem, index) => {
if(index !=0)
return prItem;
const subItems = prItem.subItems.map((si,idx)=>{
return idx != 0 ? si : {...si,isProcessing: false}
});
return { ...prItem, isProcessing: false, subItems:subItems }
}
)
}
)
}

How to update deeply nested array of objects?

I have the following nested array of objects:
const data = [
{
product: {
id: "U2NlbmFyaW9Qcm9swkdWN0OjEsz",
currentValue: 34300,
},
task: {
id: "R2VuZXJpY1Byb2R1Y3Q6MTA",
name: "My Annuity",
},
instrumentDetails: [
{
instrument: {
id: "U2NlbmFyaW9JbnN0cnVtZW50OjEz",
supplier: {
id: "U3VwcGxpZXJJbnN0cnVtZW50OjUzNjQ",
supplierDetails: {
name: "Local - Class A",
},
},
currentValue: 44323,
},
assets: {
current: 1.2999270432626702,
fixed: 0.5144729302004819,
financial: 0.0723506386331588,
cash: 0.00006003594786398524,
alternative: 0.05214078143244779,
property: 0.548494862567579,
local: 0.10089348539739094,
global: 0,
},
},
],
},
{
product: {
id: "U2NlbmFyaW9Qcm9swkfefewdWN0OjEsz",
currentValue: 3435300,
},
task: {
id: "R2VuZXJpYfewfew1Byb2R1Y3Q6MTA",
name: "Living",
},
instrumentDetails: [
{
instrument: {
id: "U2NlbmFyadewwW9JbnN0cnVtZW50OjEz",
supplier: {
id: "U3VwcGxpZdwdwXJJbnN0cnVtZW50OjUzNjQ",
supplierDetails: {
name: "Local - Class B",
},
},
currentValue: 434323,
},
assets: {
current: 1.294353242,
fixed: 0.514434242004819,
financial: 0.07434286331588,
cash: 0.0000434398524,
alternative: 0.05242348143244779,
property: 0.543242567579,
local: 0.100432439739094,
global: 0,
},
},
],
},
];
The above data presents an array of products which consist of instruments that are described in instrumentDetails array. I am trying to find an instrument by supplier id and update its assets by multiplying all of the asset values by a given number.
Here is my function:
export const updateObject = (
productsArr: any,
supplierInstrumentId: string
) => {
return productsArr.map(
(product: any) => {
product.instrumentDetails.map(
(instrumentDetail: any) => {
if (
instrumentDetail.instrument.supplier.id ===
supplierInstrumentId
) {
instrumentDetail.assets.current = instrumentDetail.assets.current + 5;
instrumentDetail.assets.fixed= instrumentDetail.assets.fixed+ 5;
instrumentDetail.assets.financial= instrumentDetail.assets.financial+ 5;
instrumentDetail.assets.cash= instrumentDetail.assets.cash+ 5;
}
}
);
}
);
};
This function is giving an error :
Uncaught TypeError: Cannot assign to read only property 'current' of
object '#'
How can I deeply update the above data? Please help.
You need to return a new instrumentDetail-type object from the map function. Don't try to update the existing object.
(instrumentDetail: any) => {
const assets = instrumentDetail.instrument.supplier.id === supplierInstrumentId
? Object.fromEntries(
Object.entries(instrumentDetail.assets).map(([k, v]) => [k, v + 5])
)
:
instrumentDetail.assets;
return {
...instrumentDetail,
assets
};
}
Your product map is not returning which is why you're likely getting an undefined. I wasn't getting the typescript error which you mentioned above. This should leave the array in the state at which you intended.
const updateObject = (
productsArr: any,
supplierInstrumentId: string
) => {
return productsArr.map(
(product: any) => {
product.instrumentDetails.map(
(instrumentDetail: any) => {
if (
instrumentDetail.instrument.supplier.id ===
supplierInstrumentId
) {
instrumentDetail.assets.current += 5;
instrumentDetail.assets.fixed= instrumentDetail.assets.fixed+ 5;
instrumentDetail.assets.financial= instrumentDetail.assets.financial+ 5;
instrumentDetail.assets.cash= instrumentDetail.assets.cash+ 5;
return instrumentDetail;
}
}
);
return product;
}
);
};

How to exclude certain property from the list in NodeJS

I'm having the below list and I would like to add only these property names PRODUCT_TYPE, PRODUCT_TERM, PRODUCT_ID in myProduct. I want to ignore rest of the properties - I've around 100 properties and want to filter only a few of them from myProduct
Please find my code below:
const obj = {
myProduct: [
{
name: "PRODUCT_PRICE",
value: "234.324",
},
{
name: "PRODUCT_NAME",
value: "Insurance",
},
{
name: "PRODUCT_TYPE",
value: "Life",
},
{
name: "PRODUCT_TERM",
value: "Long",
},
{
name: "PRODUCT_ID",
value: "AP3232343JKD",
},
{
name: "PRODUCT_ENABLED",
value: "TRUE",
},
],
};
const allowedNames = [
'PRODUCT_TYPE',
'PRODUCT_TERM',
'PRODUCT_ID'
];
const updateCertainProperties = {
PRODUCT_ID: "app.productID",
PRODUCT_ENABLED: "app.product.enabled"
};
const productName = "testProduct_3234dfasfdk3msldf23";
const environment = obj.myProduct.map((o) => {
obj.myProduct.filter(product => allowedNames.includes(product.name));
if (updateCertainProperties[o.name]) o.name = updateCertainProperties[o.name];
if (o.name === "PRODUCT_NAME") o.value = productName;
return obj.myProduct;
});
console.log(obj.myProduct)
Expected output:
[
{ name: 'PRODUCT_NAME', value: 'testProduct_3234dfasfdk3msldf23' },
{ name: 'PRODUCT_TYPE', value: 'Life' },
{ name: 'PRODUCT_TERM', value: 'Long' },
{ name: 'app.productID', value: 'AP3232343JKD' },
{ name: 'app.product.enabled', value: 'TRUE' }
]
Can someone please help me how can I achieve this? Appreciated your help in advance!
You can create an array of allowed names and filter them out using includes()
css just for prettier output
UPDATE
added updateCertainProperties object values into allowedNames array and moved filter outside environment map.
const obj = {
myProduct: [
{
name: "PRODUCT_PRICE",
value: "234.324",
},
{
name: "PRODUCT_NAME",
value: "Insurance",
},
{
name: "PRODUCT_TYPE",
value: "Life",
},
{
name: "PRODUCT_TERM",
value: "Long",
},
{
name: "PRODUCT_ID",
value: "AP3232343JKD",
},
{
name: "PRODUCT_ENABLED",
value: "TRUE",
},
],
};
const allowedNames = [
'PRODUCT_TYPE',
'PRODUCT_TERM',
'PRODUCT_NAME'
];
const updateCertainProperties = {
PRODUCT_ID: "app.productID",
PRODUCT_ENABLED: "app.product.enabled"
};
allowedNames.push(...Object.values(updateCertainProperties));
const productName = "testProduct_3234dfasfdk3msldf23";
const environment = obj.myProduct.map((o) => {
if (updateCertainProperties[o.name]) o.name = updateCertainProperties[o.name];
if (o.name === "PRODUCT_NAME") o.value = productName;
return obj.myProduct;
});
obj.myProduct = obj.myProduct.filter(product => allowedNames.includes(product.name));
console.log(obj.myProduct)
.as-console-wrapper {
max-height: unset !important;
top: 0;
}
It sounds like you're describing filtering an array, not "excluding properties". You have an array of objects, with each object consisting of a name property and value property. And you only want objects with specific values in their name property.
Using .filter on the array, it might look something like this:
obj.myProduct = obj.myProduct.filter(p => (
p.name === 'PRODUCT_TYPE' ||
p.name === 'PRODUCT_TERM' ||
p.name === 'PRODUCT_ID'));
This would filter out all elements of the array which don't match the supplied condition.

JS: Filter() Array of Objects based on nested array in object?

The data
const data = [
{
id: 1,
title: "Product Red",
inventoryItem: {
inventoryLevels: {
edges: [{ node: { location: { name: "Warehouse Red" } } }],
},
},
},
{
id: 2,
title: "Product Blue",
inventoryItem: {
inventoryLevels: {
edges: [{ node: { location: { name: "Warehouse Blue" } } }],
},
},
},
];
let result = data.filter((product) => {
return product.inventoryItem.inventoryLevels.edges.forEach((inventoryLevel) => {
return inventoryLevel.node.location.name !== "Warehouse Blue";
});
});
console.log(result);
What I want to do is filter by location name. I am not sure how to construct filtering based on nested arrays.
So the result I want is if the location isn't Warehouse Blue. data should just have the object where location name is warehouse red.
You should get your work done using findIndex() instead of your forEach.
This method would search and return the index of your condition, if is not found it will return -1
let result = data.filter(product => product.inventoryItem.inventoryLevels.edges.findIndex(item => item.node.location.name !== "Warehouse Blue") !== -1 )
let result = data.filter((product) => {
return product?.inventoryItem?.inventoryLevels?.edges
.some(edge => edge?.node?.location?.name !== ('Warehouse Blue'))
});
Can use lodash too Lodash: how do I use filter when I have nested Object?

How to filter in two deep arrays

I'm looking to filter in two deep arrays, actually my JSON:
{
"0": {
"product":[{
"uuid":"uid",
"name":"Rice"
},
{
"uuid":"uid",
"name":"Pasta"
}]
},
"1": {
"product":[{
"uuid":"uid",
"name":"Milk"
}]
}
}
I would like to get something like that when I filter with the word "ric":
{
"0": {
"product":[{
"uuid":"uid",
"name":"Rice"
}]
}
}
But I got this result:
{
"0": {
"product":[{
"uuid":"uid",
"name":"Rice"
},
{
"uuid":"uid",
"name":"Pasta"
}]
}
}
My code:
dataSort.categories = the json and
event.target.value.toLowerCase() = the specific word
dataSort.categories.filter(s => s.products.find(p => p.name.toLowerCase().includes(event.target.value.toLowerCase())));
You can achieve this with a combination of reduce and filter
var input = {
"0": {
"product":[{
"uuid":"uid",
"name":"Rice"
},
{
"uuid":"uid",
"name":"Pasta"
}]
},
"1": {
"product":[{
"uuid":"uid",
"name":"Milk"
}]
}
}
var search = "ric"
var result = Object.entries(input).reduce( (acc, [key,val]) => {
found = val.product.filter(x => x.name.toLowerCase().includes(search.toLowerCase()))
if(found.length){
acc[key] = {...val, product: found}
}
return acc
},{})
console.log(result)
There is many approach to do this, one is to map your top level array to the subArrays filtered results then filter it after:
dataSort.categories
.map(s => s.products.filter(p => p.name.toLowerCase().includes(event.target.value.toLowerCase())))
.filter(s => !!s.products.length);
You may also prefer to get a "flat" array as result because it is easier to use after :
dataSort.categories
.reduce((acc, s) => [...acc, s.products.filter(p => p.name.toLowerCase().includes(event.target.value.toLowerCase()))], []);
Please find below the code to filter out values inside the product.name and only return the value which are matching the equality condition in product array.
const json = [
{
product: [
{
uuid: "uid",
name: "Rice",
},
{
uuid: "uid",
name: "Pasta",
},
],
},
{
product: [
{
uuid: "uid",
name: "Milk",
},
],
},
];
const inputValue = "rIc";
const filteredArray = [];
json.map((s) => {
const item = s.product.find((p) =>
p.name.toLowerCase().includes(inputValue.toLowerCase())
);
item && filteredArray.push({ product: item });
});
console.dir(filteredArray);
Your dataset is an Object, not an Array and the filter is an Array method. You can use reduce by looping on the object values by Object.values then filter your products array.
const data = {
'0': {
product: [
{
uuid: 'uid',
name: 'Rice',
},
{
uuid: 'uid',
name: 'Pasta',
},
],
},
'1': {
product: [
{
uuid: 'uid',
name: 'Milk',
},
],
},
};
const keyword = 'ric';
const dataset = Object.values(data);
const results = dataset.reduce((acc, item, index) => {
const search = keyword.toLowerCase();
const product = item.product.filter(product => product.name.toLowerCase().includes(search));
if (product.length) acc[index] = { ...item, product };
return acc;
}, {});
console.log(results);

Categories

Resources