How can I populate a field dependent on the values from four other fields?

Viewed 43

I have a field, RoadmapType, which is populated with a hardcoded string based on the combination of values from four other fields, InvestmentCategory, FundingClass, InvestmentClass & Lifecycle. The value determining RoadmapType can vary, for example, in one instance, to get the RoadmapType "Incremental", the value of InvestmentCategory can be either "Enterprise" or "IT Roadmap", and the value of InvestmentClass can be "Transform", "Scale", "NPI" or "Run".

Right now, I am doing this the long way, where I am using multiple if blocks for each potential RoadmapType. I want a shorter, more reliable method to get my desired out come.

This table shows 3 example combinations and the resulting RoadmapType. Please note that only one value from each column can be used at a time.

Investment Category Funding Class Investment Class Lifecycle Roadmap Type
Enterprise Roadmap, IT Roadmap Incremental Transform, Scale, NPI, Run Any value Incremental
Enterprise Roadmap Roadmap Transform, NPI All except DD Roadmap - BAT
Enterprise Roadmap Chargeback Transform, Scale, NPI, Run IPT, SDM Chargeback - DTS

These are the if blocks I am using to get a RoadmapTypeof "Compliance".

const onTextChange = (e) => {
    var id = e.target.id ? e?.target.id : e?.target.name;
    var value = e.target.value;
    function setRoadmapType(fieldId, fieldVal, roadmapTypeVal) {
        setDetails({ ...details, [fieldId]: fieldVal, RoadmapType: roadmapTypeVal });
    }
    if (
        id === "InvestmentClass" &&
        value === "Compliance" &&
        details?.FundingClass === "Roadmap" &&
        details?.InvestmentCategory === "Enterprise Roadmap"
    ) {
        setRoadmapType(id, value, "Roadmap - Compliance");
    } else if (
        id === "FundingClass" &&
        value === "Roadmap" &&
        details?.InvestmentClass === "Compliance" &&
        details?.InvestmentCategory === "Enterprise Roadmap"
    ) {
        setRoadmapType(id, value, "Roadmap - Compliance");
    } else if (
        // ! NOT WORKING when investment category is input as the deciding value of RoadmapType
        id === "InvestmentCategory" &&
        value === "Enterprise Roadmap" &&
        details?.InvestmentClass === "Compliance" &&
        details?.FundingClass === "Roadmap"
    ) else {
        setDetails({ ...details, [id]: value });
    }
}
1 Answers

I would start by extracting the calculation logic into a strategy design pattern. This design pattern isolates the algorithm, independently from clients that may use it.

const onTextChange = (e) => {
    var id = e.target.id ? e?.target.id : e?.target.name;
    var value = e.target.value;
    function setRoadmapType(fieldId, fieldVal, roadmapTypeVal) {
        setDetails({ ...details, [fieldId]: fieldVal, RoadmapType: roadmapTypeVal });
    }
    let computedValue = RoadmapTypeStrategy.computeType(id, value, details);
    setRoadmapType(id, value, computedValue);
}


//First version of RoadmapTypeStrategy.js - computational logic extracted into a Strategy
const computeType = (id, value, details) => {
if (
    id === "InvestmentClass" &&
    value === "Compliance" &&
    details?.FundingClass === "Roadmap" &&
    details?.InvestmentCategory === "Enterprise Roadmap"
) {
    return "Roadmap - Compliance";
} else if (
    id === "FundingClass" &&
    value === "Roadmap" &&
    details?.InvestmentClass === "Compliance" &&
    details?.InvestmentCategory === "Enterprise Roadmap"
) {
    return "Roadmap - Compliance";
} else if (
    id === "InvestmentCategory" &&
    value === "Enterprise Roadmap" &&
    details?.InvestmentClass === "Compliance" &&
    details?.FundingClass === "Roadmap"
) else {
    return "default";
}
};
const RoadmapTypeStrategy = {
    computeType
};
export default RoadmapTypeStrategy;

Then, IF the total number of combinations is not too large, the best way I can think of to avoid all those if statements is by creating a class with 4 fields containing the possible combination values, and 1 field for the value. You can then compare them and fetch the value if the objects match. The downside is you need to create 1 instance of the Combination class per possible values combination.

//Final version of RoadmapTypeStrategy.js - adds more concise conditions tests via an array of objects
class Combination {
    constructor(investmentCategory, fundingClass, investmentClass, lifecycle, value) {
        this.investmentCategory = investmentCategory;
        this.fundingClass = fundingClass;
        this.investmentClass = investmentClass;
        this.lifecycle = lifecycle;
        this.value = value;
    }
    matches(invCat, funClass, invClass, lifecycle) {
        return (this.investmentCategory === invCat && this.fundingClass === funClass && this.investmentClass === invClass && this.lifecycle === lifecycle);
    }
}

const combinations = [
    new Combination('Enterprise Roadmap', 'Incremental', 'Transform', 'IPT', 'Incremental'),
    new Combination('a', 'b', 'c', 'd', 'e'),
    new Combination(/* etc */)
];

const matches = (combination, arg1, arg2, arg3, arg4) => {
    return combination.matches(arg1, arg2, arg3, arg4);
};

const computeType = (id, value, details) => {
    return (combinations.some((c) => matches(c, id, value, details?.FundingClass, details?.InvestmentCategory)) ) ?
        combinations.find((c) => matches(c, id, value, details?.FundingClass, details?.InvestmentCategory)).value :
    'default value';
};
const RoadmapTypeStrategy = {
    computeType
};
export default RoadmapTypeStrategy;

Let me know if this helps, and is clear enough.

Related