Skip to content

Web App with Node.js and Express

If you've ever needed to build an interactive organizational chart for the web, using Node.js with OrgChartJS is a powerful combination.

In this quick tutorial, we will build a simple app that lets you view, add, edit, and delete team members, with data stored in a JSON file on the server.

Step 1: Set Up the Project

Create a new folder with this structure:

text
my-orgchart-app/
├── public/
│   ├── index.html
│   ├── json.json
│   └── script.js
└── server.js

Initialize the project and install Express:

bash
npm init -y
npm install express

Step 2: Create the Frontend

In public/index.html, load OrgChartJS and your script:

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Org Chart</title>
  <script src="https://cdn.balkan.app/orgchart.js"></script>
</head>
<body>
  <div id="tree"></div>
  <script src="script.js"></script>
  <style>
    html, body, #tree {
      width: 100%;
      height: 100vh;
    }       
  </style>
</body>
</html>

In public/script.js, initialize the chart and handle add, update, and remove events:

javascript
let chart = new OrgChart(document.getElementById("tree"), {
  nodeBinding: {
    field_0: "name",
    field_1: "title"
  },
  nodeMenu: {
    add: { text: "Add New" },
    edit: { text: "Edit" },
    remove: { text: "Remove" }
  }
});

chart.onUpdateNode(function(args) {
  fetch('/api/update', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(args)
  });
});

chart.onRemoveNode(function(args) {
  fetch('/api/remove', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ args })
  });
});

chart.onAddNode(function(args) {
  fetch('/api/add', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(args.data)
  });
});

fetch('json.json')
  .then(response => response.json())
  .then(data => chart.load(data));

Add initial data in public/json.json:

json
[
  { "id": 1, "name": "Amber McKenzie" },
  { "id": 2, "pid": 1, "name": "Ava Field" },
  { "id": 3, "pid": 1, "name": "Peter Stevens" }
]

Step 3: Create the Server

In server.js, create an Express server and add simple API routes to update the JSON file:

javascript
const express = require('express');
const path = require('path');
const fs = require('fs');

const app = express();
const PORT = 3000;
const DATA_PATH = path.join(__dirname, 'public', 'json.json');

app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());

function readData() {
  return JSON.parse(fs.readFileSync(DATA_PATH, 'utf8'));
}

function writeData(data) {
  fs.writeFileSync(DATA_PATH, JSON.stringify(data, null, 2));
}

app.post('/api/update', (req, res) => {
  const updatedNode = req.body.newData;
  let data = readData();
  data = data.map(node => node.id === updatedNode.id ? { ...node, ...updatedNode } : node);
  writeData(data);
  res.json({ status: 'updated', node: updatedNode });
});

app.post('/api/remove', (req, res) => {
  const nodeId = req.body.args.id;
  const { newPidsForIds = {} } = req.body.args.newPidsAndStpidsForIds || {};
  let data = readData();

  data = data.map(node => (
    Object.prototype.hasOwnProperty.call(newPidsForIds, node.id)
      ? { ...node, pid: newPidsForIds[node.id] }
      : node
  ));
  data = data.filter(node => node.id !== nodeId && node.pid !== nodeId);

  writeData(data);
  res.json({ status: 'removed', id: nodeId });
});

app.post('/api/add', (req, res) => {
  const newNode = req.body;
  let data = readData();
  data.push(newNode);
  writeData(data);
  res.json({ status: 'added', node: newNode });
});

app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
});

Step 4: Run the App

Start the server:

bash
node server.js

Then open localhost in your browser.

You can now add, edit, and remove people in the chart, and your changes will be saved back to json.json.

This setup is perfect for prototyping org charts or building an internal hierarchy editor.

From here, you can extend it with a real database, authentication, and role-based permissions.