Home > front end >  Adding table properties to objects in array dynamically
Adding table properties to objects in array dynamically

Time:04-23

I'm drawing a table dynamically from an array of objects, each object should have a left, center and right properties which are object as well.

I want to compare the object ahead to the objects that follows and find if any property is missing, if there are, I want to add rowSpan with the missing difference.

For example: This

const arr =[
{Left:{},Center:{},Right:{}},
{Right:{}},
{Left:{},Right:{}},
{Left:{}},
{Left:{}}
]

Should look like

const arr =[
{Left:{rowSpan:2},Center:{rowSpan:5},Right:{}},
{Right:{}},
{Left:{},Right:{rowSpan:3}},
{Left:{}},
{Left:{}}
]

I also want add alignment accordingly, so if I added rowSpan to an object key where that key can be still be found in the object that follows, I want to add align:bottom to it, if it was the last key then I should add align:top and if it's the only key of it's kind I want to add align:center

For example:

const arr =[
{Left:{},Center:{},Right:{}},
{Right:{}},
{Left:{},Right:{}},
{Left:{},},
{Left:{}}
]

Should look like

const arr =[
{Left:{align:bottom},Center:{align:center},Right:{}},
{Right:{}},
{Left:{},Right:{align:top}},
{Left:{}},
{Left:{}}
]

CodePudding user response:

Provided below is one possible solution that achieves the desired objective.

Code Snippet

// helper method to transform the objects
// by adding row-span or align or both
const getNewValue = (k, v, idx, vmap, aLen, typ = 'both') => {
  // here "k" can only be "Left", "Center" or "Right"
  // get index of current element's "idx" on the "map" (parameter: "vmap")
  const currKi = vmap[k].findIndex(i => i === idx);
  // find where the next key (ie, Left, Center or Right) is present
  // by using the "map"
  const nextK = (
    currKi >= 0
    ? currKi   1 < vmap[k].length
      ? vmap[k][currKi   1]       // if "vmap" has the next Left, Center or Right
      : aLen                      // if "vmap" doesn't have the next L, C or R
    : -1                // if "vmap" doesn't have current "idx"
  );
  // determine the new alignment, if applicable
  const align = (
    vmap[k].length === 1
      ? 'center'
      : nextK === aLen
        ? 'top'
        : nextK >= 0
          ? 'bottom'
          : undefined
  );
  return (
    nextK >= 0 && nextK - idx > 1     // if row-span needs to be added
    ? {
        ...v,
        ...(            // add row-span if "typ" is "both" or "span"
          ['both', 'span'].includes(typ)
          ? { rowSpan: nextK - idx }      // the "number" is computed here
          : {}
        ),
        ...(            // add align if "typ" is "both" or "align"
          ['both', 'align'].includes(typ)
          ? { align }         // populate the "align"
          : {}
        )
      }
    : v
  );
};

// method to calculate row-span and/or align
const spanAndAlign = (arr, typ = 'both') => {
  // first construct a map/dictionary
  // Left: [0, 2, 3, 4]
  // Center: [0]
  // Right: [0, 1, 2]
  // keys are L, C or R. 
  // values are arrays of index where each occurs in "arr" array
  const lcrMap = arr.reduce(
    (map, obj, idx) => {
      Object.keys(map).forEach(k => {
        if (k in obj) map[k].push(idx);
      });
      return map;
    },
    {Left: [], Center: [], Right: []}
  );
  // use the "lcrMap" to transform the given array
  const res = arr.map(
    (obj, idx) => (
      Object.fromEntries(
        Object.entries(obj).map(
          ([k, v]) => ([
            k,
            ['Left', 'Center', 'Right'].includes(k)     // only transform L, C or R
            ? getNewValue(k, v, idx, lcrMap, arr.length, typ)
            : v
          ])
        )
      )
    )
  );
  return res;
};

const origArr = [{
    Left: {},
    Center: {},
    Right: {}
  },
  {
    Right: {}
  },
  {
    Left: {},
    Right: {}
  },
  {
    Left: {}
  },
  {
    Left: {}
  }
];

console.log('get Span Only: ', spanAndAlign(origArr, 'span'));
console.log('get Align Only: ', spanAndAlign(origArr, 'align'));
console.log('get Span & Alighn: ', spanAndAlign(origArr));
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Inline comments provided in the above snippet

NOTE

This solution employs a number of JS concepts/features such as .reduce(), .map(), Object.fromEntries(), Object.entries(), .findIndex(), .includes(), ... spread, ?: ternary operator, etc.

  • Related