I need to return part of the object which meet some condition. I get API response with the following example:
const response: ApiResponse = {
valid: true,
start: false,
stop: true
};
And based on that response I need to check my configuration object and check if there is some object witch meets the response. My config looks like this (can be modified if there is a better way to model it)
public readonly modalDataConfig: ModalDataConfig[] = [
{
conditions: [
{
start: true,
valid: true,
},
],
p1: {
title: `Name p1 A`,
description: `description p1 A`,
},
p2: {
title: `Name p2 B`,
description: `description p2 B`,
},
},
{
conditions: [
{
valid: false,
stop: true,
},
],
p1: {
title: `Name p1 C`,
description: `description p1 C`,
},
p2: {
title: `Name p2 C`,
description: `description p2 C`,
},
},
{
conditions: [
{
start: false,
valid: false,
},
],
p1: {
title: `Name p1 D`,
description: `description p1 D`,
},
p2: {
title: `Name p2 D`,
description: `description p2 D`,
},
},
];
So I need to check if there is an object inside of the modalDataConfig.conditions which meets the response conditions. If yes I need to return either p1 or p2 from that object. I get always 3 conditions from API but my configuration condition usually uses just 2 of them. So I need to check keys and values. In the example I should get the first object since it conditions array has start: true and valid: true. TSPlayground Edit: I need to return p1 or p2 from the correct object based on the param which I know beforehand. So in the example I can assume:
const context = Producer.P1;
where AppContext is enum
enum Producer {
P1 = 'p1',
P2 = 'p2',
}
CodePudding user response:
To find an object that satisfies conditions, you need decompose each conditions
object into key
and value
and compare their result with the target value in the ApiResponse
modalDataConfig=[{conditions:[{start:true,valid:true}],p1:{title:`Name p1 A`,description:`description p1 A`},p2:{title:`Name p2 B`,description:`description p2 B`}},{conditions:[{valid:false,stop:true}],p1:{title:`Name p1 C`,description:`description p1 C`},p2:{title:`Name p2 C`,description:`description p2 C`}},{conditions:[{start:false,valid:false}],p1:{title:`Name p1 D`,description:`description p1 D`},p2:{title:`Name p2 D`,description:`description p2 D`}}];
ApiResponse = {valid: true, start: true, stop: true};
const { p1, p2 } = modalDataConfig.find(({ conditions }) =>
Object.entries(conditions.at(0))
.every(([key, value]) => ApiResponse[key] === value));
console.log('P1 is:', p1, 'P2 is:', p2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
CodePudding user response:
Edit
We can also simplify my solution based on a commenter's suggestion! This function removes the need to use 1/0 and simply checks if all the elements in the array are truthy.
const checkResponse = (modalDataConfig, response) => {
let res = []
for (const conf of modalDataConfig) {
let cond = conf.conditions
let isSame = Object.keys(cond)
.map(key => response?.[key] == cond[key]).every(Boolean)
if (isSame) res.push(conf)
}
return res
}
Note
In my solution, I am assuming that we only care if the key:value pairs in the conditions of the config are the same as the key:value pairs in the response, and not the other way around. This means that if there exists a key in response but not in the config, we do not use that key for our similarity check.
Steps
I would first change how the ModelDataConfig is modeled, by replacing the value of the
condition
key to just be an object instead of an array of objects.I will first iterate through each element in
modelDataConfig
Within the
conditions
object of each element, I compare its key:value with theresponse
, by checking 2 conditions - (1) if the key exists inresponse
and if the value of that key is the same in both the element andresponse
. If it satisfies both of this condition, I return a 1, else a 0. At the end, I get an array of 1s and 0s.For the
response
to satisfy theconditions
, there can only be 1s in the array, because having a zero means that either they key doesn't even exist in theresponse
, or the keys have different values. To check if there are only 1s, I reduce the array by using a bitwise AND operator.If the final result after reduction is 1, it means that the particular element of the
modelDataConfig
is the one you are looking for.
Example
const modalDataConfig = [{
conditions: {
start: true,
valid: true,
},
p1: {
title: `Name p1 A`,
description: `description p1 A`,
},
p2: {
title: `Name p2 B`,
description: `description p2 B`,
},
},
{
conditions: {
valid: false,
stop: true,
},
p1: {
title: `Name p1 C`,
description: `description p1 C`,
},
p2: {
title: `Name p2 C`,
description: `description p2 C`,
},
},
{
conditions: {
start: false,
valid: false,
},
p1: {
title: `Name p1 D`,
description: `description p1 D`,
},
p2: {
title: `Name p2 D`,
description: `description p2 D`,
},
},
{
conditions: {
start: false,
valid: true,
},
p1: {
title: `Name p1 D`,
description: `description p1 D`,
},
p2: {
title: `Name p2 D`,
description: `description p2 D`,
},
},
];
const checkResponse = (modalDataConfig, response) => {
let res = []
for (const conf of modalDataConfig) {
let cond = conf.conditions
let isSame = Object.keys(cond)
.map(key => key in response && response[key] == cond[key] ? 1 : 0)
.reduce((a, b) => a & b, 1)
if (isSame) res.push(conf)
}
return res
}
const response1 = {
valid: true,
start: false,
stop: true
};
console.log('Results with response1:')
console.log(checkResponse(modalDataConfig, response1))
const response2 = {
valid: false,
stop: true
};
console.log('Results with response2:')
console.log(checkResponse(modalDataConfig, response2))