Skip to main content Skip to footer

How to Update a PostgreSQL Database from a JavaScript Datagrid

Quick Start Guide
What You Will Need

Wijmo | VisualStudio Code | NPM

Node.JS | PostgreSQL | Express

CORS | node-postgress

Controls Referenced
Tutorial Concept Implement a PostgreSQL JavaScript workflow by capturing DataGrid state changes, issuing asynchronous POST requests, and processing updates through an Express API to reliably persist validated, row-level modifications in PostgreSQL.

Displaying data from a database in a JavaScript datagrid is only part of the story. In real-world applications, users don't just view data; they also edit it. Whether you're building administrative tools, internal dashboards, or line-of-business applications, those changes need to be safely and reliably persisted back to the database.

In a previous article, "Connecting Your JavaScript DataGrid to a PostgreSQL Database with Express," we walked through how to retrieve data from a PostgreSQL database using an Express API and display it in Wijmo's FlexGrid. That article focused on the read side of the equation: querying data from the server and loading it into a high-performance JavaScript datagrid. While this article builds on the same architecture, it shifts the focus to the write path and updating your PostgreSQL database after a user edits data in the grid.

In this article, we'll explore how to capture user edits in a JavaScript datagrid and send them back to the server via an asynchronous POST request. From there, we'll show how an Express endpoint can process those updates and apply them to the appropriate rows in a PostgreSQL table based on each record's unique identifier. Along the way, we'll cover common patterns and best practices for handling editable grid data, including change tracking, request validation, and safe updates to relational data.

What This Article Covers

By the end of this article, you'll have a clear understanding of how to implement a full read/write data workflow between a JavaScript datagrid and PostgreSQL. Specifically, we'll cover:

This walkthrough assumes a basic familiarity with JavaScript, Express, and PostgreSQL. If you've already read the earlier article on connecting FlexGrid to PostgreSQL, the setup will feel familiar. Still, even if you haven't, the concepts and patterns presented here can be applied to any JavaScript datagrid backed by a relational database.

Let's start by looking at how Wijmo FlexGrid tracks user edits and how we can collect only the changes that need to be saved.

Ready to get started? Download Wijmo Today!

Detecting and Collecting Edited Rows

The first thing we'll need to do is set up our JavaScript datagrid to track changes users make. Thankfully, Wijmo's FlexGrid makes it easy through the CollectionView, its data management object.

In the previous article, in the application's main.js file, we set up our CollectionView object and assigned it to our FlexGrid control:

const cv = new wjCore.CollectionView([]);
const grid = new wjGrid.FlexGrid('#dataGrid', {
  itemsSource: cv
});

From there, we made an API call to our Express server, which loaded data into the empty CollectionView to display within the grid.

To add change-tracking functionality to the CollectionView, we simply add a single property to the CollectionView's initialization process: trackChanges.

const cv = new wjCore.CollectionView([], {
  trackChanges: true
});

Now, the CollectionView will track each data object that a user changes and store them in its itemsEdited property, an array of data objects.

Sending Edited Data to an Express Server Using a POST Request

Now that we can track changes, it's time to create a method that posts them to the server. First, we're going to add a button element and tie an event listener to the element:

document.querySelector('#app').innerHTML = `
  <div>
    <h2>Wijmo FLexGrid with Express and PostgreSQL</h2>
    <div id="dataGrid"></div><br/>
    <button id="submit" class="btn btn-primary">Save Updates</button>
  </div>
`
const submitButton = document.getElementById('submit');
submitButton.addEventListener('click', sendDataToServer);

Here, we've added a button with an ID of submit, which we then reference in our JavaScript to associate it with a variable. From there, we add a click event listener that, when called, will trigger our sendDataToServer() method.

Now, we have to set up that method so that our changes get fired off to the server:

async function sendDataToServer() {
  var items = [];
  for(var i = 0; i < cv.itemsEdited.length; i++) {
    items.push(cv.itemsEdited[i]);
  }
  const response = await fetch('http://localhost:3000/ford', {
    method: 'POST',
    headers: {
      'Content-Type': 'application.json'
    },
    body: JSON.stringify(items)
  });
  if(!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }
  const result = await response.json();
  console.log(result);
}

Now, you may be wondering why we're iterating through the itemsEdited array and pushing each value into a new array: it's because the itemsEdited array is an Observable Array, which we can't send in our POST request. So, we pull each value from the itemsEdited array and add it to a new array to send to the server.

After creating our new array, the rest of the method is very straightforward. We await our fetch request, which includes the method type (POST), sets the header, and passes our array through as the body.

With that complete, the JavaScript application is set to allow users to send their edited values to an Express server. Now, we need to set up the server so it can both accept this POST method and take the array it receives and update our PostgreSQL database.

Processing Arrays of Updates on the Express Server

If you're not familiar with the database that we created in the previous article, here's what we're working with as far as fields and values in our database's ford table:

JavaScript Datagrid

The data above is what we're loading into our JavaScript datagrid, and it will be updated when we make changes in Wijmo's FlexGrid and commit them back to the database.

With the JavaScript application set up to make a POST request with data in the body, we can now move on to editing the Express server to be ready to receive that POST request. Inside the server's index.js file, add the following method:

app.post('./ford', async (req, res) => {
  // POST Method
});

Now, when a POST request comes in to the URL http://localhost:3000/ford, our server will call this method.

Next, we'll add the code below to do some basic processing of the body of the POST request so that we can be sure the proper data was included:

app.post('./ford', async (req, res) => {
  const updates = req.body;
  if(!Array.isArray(updates)) {
    return res.status(400).json({ error: 'Expected an array' });
  }
  const allowedCols = new Set([
    'model',
    'trim',
    'body_type',
    'vehicle_type',
    'engine_type',
    'fuel_type',
  ]);
});

Here, we store the request body in a variable named updates, and then check that its contents are a valid array. If it's not an array, we send a response to the client letting them know the server received an incorrect value.

We're also adding a variable called allowedCols; this Set determines which database columns can be updated by the POST request.

Updating Rows in PostgreSQL Using Parameterized Queries

Now that the Express server's POST method is created and the array is being validated, we can move on to setting up our try/catch statement inside of the method, which will handle sending the query to the database:

try {
  await db.query('BEGIN');
  let updatedCount = 0;
  const missingIds = [];
  for(const row of updates) { ... }
  await db.query('COMMIT');
  return res.json({ ok: true, updatedCount, missingIds });
} catch(err) {
  await db.query('ROLLBACK');
  res.status(500).json({ ok: false, error: err.message });
}

There are a few things we need to consider here. First, db.query('BEGIN') initiates our database transaction. The reason that we're doing this is that we're going to be iterating through the list of rows to make these updates. If there are any errors during this process, we drop into the catch statement and use db.query('ROLLBACK') to undo all of the SQL statements that we've run.

Beneath the initiation of the database transaction, we're also initializing a few variables to track how many rows are updated and whether any objects are missing an ID and can't be sent to the database. These get returned after the db.query('COMMIT'), which commits the queries to your database.

You'll notice that we also have a for loop that doesn't have anything inside. In this for loop, we'll handle the building of the SQL statement and pass it as a query for each object in the updates array:

for(const row of updates) {
  const id = row?.id;
  if(id === undefined || id === null) {
    throw new Error('Each object must include an "id".');
  }
  const fields = Object.keys(row).filter((k) => k !== 'id' && allowedCols.has(k));
  if(fields.length === 0) {
    continue;
  }
  const setClause = fields.map((col, i) => `"${col}" = $${i + 1}`).join(', ');
  const values = fields.map((col) => row[col]);
  values.push(id);
  const sql = `UPDATE ford SET ${setClause} WHERE id = $${values.length}`;
  const result = await db.query(sql, values);
  if(result.rowCount === 0) {
    missingIds.push(id);
  } else {
    updatedCount += result.rowCount;
  }
}

The fields variable builds a list of fields for each column in the database table. If we log that to the console, when we run a query, you'll see the following:

[
  'model',
  'trim',
  'year',
  'body_type',
  'vehicle_type',
  'fuel_type'
]

The setClause variable uses the fields variable we just created to build what we'll be using in our SQL SET statement. If we log that to the console, when we run a query, you'll see the following:

"model" = $1, "trim" = $2, "year" = $3, "body_type" = $4, "vehicle_type" = $5, "engine_type" = $6, "fuel_type" = $7

Finally, the values variable uses the fields variable to build each row in the database we're updating. For the test query that we ran with a single field changed, this is what it looks like when logged to the console:

[
  'MUSTANG',
  'GT',
  2022,
  'Coupe',
  'Passenger',
  'v8',
  'Gasoline',
  '5'
]

With the for loop complete, below is how the completed POST method appears in the Express server:

app.post('/ford', async (req, res) => {
    const updates = req.body;
    if(!Array.isArray(updates)) {
        return res.status(400).json({ error: 'Expected an array' });
    }
    const allowedCols = new Set([
        'model',
        'trim',
        'year',
        'body_type',
        'vehicle_type',
        'engine_type',
        'fuel_type',
    ]);
    try {
        await db.query('BEGIN');
        let updatedCount = 0;
        const missingIds = [];
        for(const row of updates) {
            const id = row?.id;
            if(id === undefined || id === null) {
                throw new Error('Each object must include an "id".');
            }
            const fields = Object.keys(row).filter((k) => k !== 'id' && allowedCols.has(k));
            if(fields.length === 0) continue;
            const setClause = fields.map((col, i) => `"${col}" = $${i + 1}`).join(', ');
            const values = fields.map((col) => row[col]);
            values.push(id);
            const sql = `UPDATE ford SET ${setClause} WHERE id = $${values.length}`;
            const result = await db.query(sql, values);
            if(result.rowCount === 0) {
                missingIds.push(id);
            } else {
                updatedCount += result.rowCount;
            }
        }
        await db.query('COMMIT');
        return res.json({
            ok: true,
            updatedCount,
            missingIds
        });
    } catch(err) {
        await db.query('ROLLBACK');
        res.status(500).json({ ok: false, error: err.message });
    }
});

Running the Application and Committing Database Updates

Once that is complete, we can run our application. Before we do, we'd like to remind you of what the database currently looks like:

PostgreSQL database

Now, running our application will bring the following view into the browser:

JavaScript Datagrid with Express and PostgreSQL

For our update, we will go through the three Mustang entries, update their year to 2026, and then click the Save Updates button:

PostgreSQL Database Update

As you can see in the console, we've been returned a success, and it looks like three entries have been updated, and zero objects were missing an associated ID value.

If we take a look at our database, we'll see the following:

Updated PostgreSQL Database

You can see from the highlighted fields that our updates have been committed to the database. Now, any changes that we make can be committed via the Save Updates button.

Conclusion

In this article, we walked through a complete write-back workflow that safely persists user edits made in a JavaScript DataGrid to a PostgreSQL database. By leveraging Wijmo FlexGrid's built-in change tracking, an asynchronous POST request, and parameterized queries in an Express API, we can update only the rows and fields that actually changed without sacrificing performance or data integrity. Wrapping the updates in a database transaction ensures consistency, while column whitelisting and request validation help protect your backend from unintended changes. With this foundation in place, you can confidently extend the pattern to support more advanced scenarios such as inserts, deletes, validation rules, or user authorization, and build fully interactive, data-driven applications backed by PostgreSQL.

Happy coding!

Ready to check it out? Download Wijmo Today!

Tags:

comments powered by Disqus