Search code examples
javascriptlodash

Use lodash cond to take certain branch


I'm trying to use lodash cond to invoke different functions provided different inputs. Perhaps I've misunderstood cond, but I really like the clean approach to conditions.

Basically I have a 2-dimensional data array (grid). A header 1-dimensional header array and a 1-dimensional totals array. The user can choose to add data headers and totals to the data array. The total row can be either at the top or bottom.

This turned into eight conditions like this:

const totalAbove = totalPosition >= 1;
const totalBelow = totalPosition <= -1;

const hasLabelsAndTotalsAbove = showLables && totalAbove;
const hasLabelsAndTotalsBelow = showLables && totalBelow;

const noLabelsAndTotalsAbove = !showLables && totalAbove;
const noLabelsAndTotalsBelow = !showLables && totalBelow;

const noTotalHasLabels = showLables && !hasTotalRow;
const noTotalNoLabels = !showLables && !hasTotalRow;

Then I thought I could do the this:

const getData = cond([
            [hasLabelsAndTotalsAbove, () => Array.prototype.concat([headers], [totalRow], ...matrixes)],
            [hasLabelsAndTotalsBelow, () => Array.prototype.concat([headers], ...matrixes, [totalRow])],
            [noLabelsAndTotalsAbove, () => Array.prototype.concat([totalRow], ...matrixes)],
            [noLabelsAndTotalsBelow, () => Array.prototype.concat(...matrixes, [totalRow]) ],
            [noTotalHasLabels, () => Array.prototype.concat([headers], ...matrixes) ],
            [noTotalNoLabels, () => matrixes ]
        ]);

data = getData();

The above should combine the three arrays into the desired form by concatenating them in the right order. But the result is just undefined. Have I completely misunderstood cond?

For now I've just turned the _cond part into if...else statements, but I find the cond approach cleaner.


Solution

  • You have to use _.matches or other function that allows you to pick a property in some object, with getData you don't have context, because you don't pass anything, and _.cond returns a function that works against an object. If you want to test if hasLabelsAndTotalsAbove is true and execute some logic, you can create an object and pass it to the function returned by _.cond:

    const totalPosition = 2;
    const showLabels = true;
    const hasTotalRow = true;
    
    const totalAbove = totalPosition >= 1;
    const totalBelow = totalPosition <= -1;
    
    const definitions = {
        hasLabelsAndTotalsAbove: showLabels && totalAbove,
        hasLabelsAndTotalsBelow: showLabels && totalBelow,
        noLabelsAndTotalsAbove: !showLabels && totalAbove,
        noLabelsAndTotalsBelow: !showLabels && totalBelow,
        noTotalHasLabels: showLabels && !hasTotalRow,
        noTotalNoLabels: !showLabels && !hasTotalRow
    };
    
    const m = a => _.matches({ [a]: true });
    
    const getData = _.cond([
        [m('hasLabelsAndTotalsAbove'), () => 'Action: hasLabelsAndTotalsAbove'],
        [m('hasLabelsAndTotalsBelow'), () => 'Action: hasLabelsAndTotalsBelow'],
        [m('noLabelsAndTotalsAbove'), () => 'Action: noLabelsAndTotalsAbove'],
        [m('noLabelsAndTotalsBelow'), () => 'Action: noLabelsAndTotalsBelow'],
        [m('noTotalHasLabels'), () => 'Action: noTotalHasLabels'],
        [m('noTotalNoLabels'), () => 'Action: noTotalNoLabels']
    ]);
    
    console.log(getData(definitions)); 
    

    This allows us to select the action to execute if some property of the object evaluates to true.