Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to update a value based on previous value in an array of objects?

I am trying to update every current value based on the previous value of another property.
Actually, I need to do the task with dates, but just to keep it simple, I’ll explain my problem with simple numbers.
I have

  1. Start, which is 1.
  2. Stop, which is already defined
  3. End
  4. Duration, which is already defined

My goal

  • Start = Duration of previous index + End of previous index
  • End = Start + Stop of current value

To illustrate, I added the screenshot of the table, how it should look like.
Desired view

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

enter image description here

Current View

enter image description here

Code below and sandbox link

import React from "react";
import { AgGridReact } from "ag-grid-react";
import "./styles.css";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css";
function App() {
  let start = 1;
  const [gridApi, setGridApi] = React.useState(null);
  const [gridColumnApi, setGridColumnApi] = React.useState(null);

  const onGridReady = (params) => {
    setGridApi(params.api);
    setGridColumnApi(params.columnApi);
  };

  const defaultColDef = {
    flex: 1,
    editable: true
  };

  const columnDefs = [
    {
      headerName: "Name",
      field: "name"
    },
    {
      headerName: "start",
      field: "updatedStart"
    },
    { headerName: "stop", field: "stop" },
    {
      headerName: "end",
      field: "end"
    },
    {
      headerName: "duration",
      field: "duration",
      colId: "duration"
    }
  ];
  const rowData = React.useMemo(
    () => [
      {
        name: "John",
        stop: 10,
        duration: 5
      },
      {
        name: "David",
        stop: 15,
        duration: 8
      },
      {
        name: "Dan",
        stop: 20,
        duration: 6
      }
    ],
    []
  );

  const rowDataWithStart = React.useMemo(() => {
    return (
      rowData &&
      rowData.map((row, i) => ({
        ...row,
        start: start
      }))
    );
  }, [start, rowData]);

  const rowDataWitEnd = React.useMemo(() => {
    return (
      rowDataWithStart &&
      rowDataWithStart.map((row, i) => ({
        ...row,
        end: row.start + row.stop
      }))
    );
  }, [rowDataWithStart]);




//this function(rowDataWitUpdatedStart) should get the previous value of end and duration and get the total
  const rowDataWitUpdatedStart = React.useMemo(() => { 
    return (
      rowDataWitEnd &&
      rowDataWitEnd.map((row, i) => ({
        ...row,
        updatedStart: row.end + row.duration
      }))
    );
  }, [rowDataWitEnd]);

  return (
    <div className="App">
      <h1 align="center">React-App</h1>
      <div className="ag-theme-alpine">
        <AgGridReact
          columnDefs={columnDefs}
          rowData={rowDataWitUpdatedStart}
          defaultColDef={defaultColDef}
          domLayout={"autoHeight"}
          onGridReady={onGridReady}
        ></AgGridReact>
      </div>
    </div>
  );
}

export default App;

I have tried to do the task making a use of valueGetter from the library I use: AG Grid, but seems to be not the best approach. See my previous question
Any help will be appreciated

>Solution :

Instead of having a step-wise transformation of your data, you can simply do all the operations you want in one go, using Array.prototype.reduce. The way we are going to use Array.prototype.reduce here is going to be almost similar to how you use Array.prototype.map (we are pushing the objects as-is into a new array, so there is no transformation of data), but the advantage is that we have access to the current index in the third argument, which allows us to access values of the previous item.

With your logic, where you want start to be the duration + end of the previous item, we can use this logic:

curCopy.start = idx === 0 ? 1 : (acc[idx - 1].duration + acc[idx - 1].end);

…which basically says:

  1. If we are on the first time, just start with the seed value of 1 for start
  2. If not, then we access the previous entry (current index minus one) of the accumulator, and access its duration and end properties. Sum them up and use them for start

Use this logic in a new memoized array of objects returned:

const updatedRowData = React.useMemo(() => {
  const updated = rowData.reduce((acc, cur, idx) => {
    const curCopy =  {...cur};
    const previous = acc[idx - 1];
    curCopy.start = idx === 0 ? 1 : (previous.duration + previous.end);
    curCopy.end = curCopy.start + curCopy.stop;
    acc.push(curCopy);
    return acc;
  }, []);

  return updated;
}, [rowData]);

And then in your template, simply use rowData={updatedRowData}.
It should generate the results that you expected:

Expected table results

I have forked your sandbox to create a proof-of-concept example:

Edit ag-grid (forked)

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading