You can create a CellBindingSource from a Data Manager table. The constructor now accepts either the table instance returned by spread.dataManager().addTable or the table name. After that, use the setBindingPath method to bind cells to fields, and then set the binding source as the worksheet data source.
For example:
When the Data Manager table contains multiple records, you can use activeRecordIndex to switch which record is currently bound to the worksheet. This is useful for detail views that display one record at a time while reusing the same cell bindings.
This sample also shows that nested collections can still be used together with cell-level binding. In the demo, the active employee record is displayed in bound cells, and a table uses bindingPath to show the current record's emergencyContacts list.
var spreadNS = GC.Spread.Sheets;
var spreadInstance;
var bindingSource;
var activeRecordIndex = 0;
var data = [
{
"empId": "EMP-001",
"fullName": "Sarah Jenkins",
"department": "Engineering",
"location": "San Francisco, USA",
"email": "sarah.j@company.com",
"emergencyContacts": [
{ "name": "David Jenkins", "relationship": "Spouse", "phone": "+1 (555) 019-2834" },
{ "name": "Mary Jenkins", "relationship": "Mother", "phone": "+1 (555) 019-5821" }
]
},
{
"empId": "EMP-002",
"fullName": "Yuki Tanaka",
"department": "Product Design",
"location": "Tokyo, Japan",
"email": "yuki.t@company.com",
"emergencyContacts": [
{ "name": "Kenji Tanaka", "relationship": "Brother", "phone": "+81 90-1234-5678" },
{ "name": "Chiyo Tanaka", "relationship": "Mother", "phone": "+81 90-8765-4321" }
]
},
{
"empId": "EMP-003",
"fullName": "Carlos Silva",
"department": "Global Sales",
"location": "Sao Paulo, Brazil",
"email": "carlos.s@company.com",
"emergencyContacts": [
{ "name": "Ana Silva", "relationship": "Spouse", "phone": "+55 11 98765-4321" },
{ "name": "Roberto Silva", "relationship": "Father", "phone": "+55 11 91234-5678" }
]
},
{
"empId": "EMP-004",
"fullName": "Amara Diallo",
"department": "Human Resources",
"location": "London, UK",
"email": "amara.d@company.com",
"emergencyContacts": [
{ "name": "Ibrahim Diallo", "relationship": "Father", "phone": "+44 7700 900077" },
{ "name": "Fatoumata Diallo", "relationship": "Sister", "phone": "+44 7700 900088" }
]
},
{
"empId": "EMP-005",
"fullName": "Liam Nguyen",
"department": "Marketing",
"location": "Singapore",
"email": "liam.n@company.com",
"emergencyContacts": [
{ "name": "Linh Nguyen", "relationship": "Spouse", "phone": "+65 9123 4567" },
{ "name": "Minh Nguyen", "relationship": "Brother", "phone": "+65 8123 4567" }
]
},
{
"empId": "EMP-006",
"fullName": "Elena Rostova",
"department": "Finance",
"location": "Berlin, Germany",
"email": "elena.r@company.com",
"emergencyContacts": [
{ "name": "Dmitry Rostov", "relationship": "Spouse", "phone": "+49 151 2345678" },
{ "name": "Olga Rostova", "relationship": "Mother", "phone": "+49 160 8765432" }
]
},
{
"empId": "EMP-007",
"fullName": "David Chen",
"department": "Legal & Compliance",
"location": "Sydney, Australia",
"email": "david.c@company.com",
"emergencyContacts": [
{ "name": "Grace Chen", "relationship": "Sister", "phone": "+61 491 570 156" },
{ "name": "Peter Chen", "relationship": "Father", "phone": "+61 491 570 157" }
]
}
];
window.onload = function () {
spreadInstance = new spreadNS.Workbook(document.getElementById("ss"), { sheetCount: 1 });
initSpread(spreadInstance);
initRecordPanel(data);
};
function initSpread(spread) {
spread.suspendPaint();
var sheet = spread.sheets[0];
applyEmployeeDetailView(sheet);
var dataManagerTable = spread.dataManager().addTable("table1", { data: data });
bindingSource = new spreadNS.Bindings.CellBindingSource(dataManagerTable);
sheet.setDataSource(bindingSource);
bindingSource.activeRecordIndex(activeRecordIndex);
spread.resumePaint();
}
function initRecordPanel(records) {
var list = document.getElementById("recordList");
if (!list) {
return;
}
list.innerHTML = "";
records.forEach(function (record, index) {
var item = document.createElement("button");
item.type = "button";
item.className = "record-item";
item.setAttribute("data-index", index);
item.setAttribute("aria-pressed", index === activeRecordIndex ? "true" : "false");
item.innerHTML =
'<span class="record-item-index">Record ' + (index + 1) + '</span>' +
'<span class="record-item-name">' + escapeHtml(record.fullName) + '</span>' +
'<span class="record-item-meta">' + escapeHtml(record.empId + " - " + record.department) + '</span>' +
'<span class="record-item-submeta">' + escapeHtml(record.location) + '</span>';
item.addEventListener("click", function () {
updateRecordIndex(bindingSource, index);
});
list.appendChild(item);
});
syncActiveRecordPanel();
}
function syncActiveRecordPanel() {
var items = document.querySelectorAll(".record-item");
for (var i = 0; i < items.length; i++) {
var item = items[i];
var isActive = Number(item.getAttribute("data-index")) === activeRecordIndex;
item.classList.toggle("active", isActive);
item.setAttribute("aria-pressed", isActive ? "true" : "false");
}
var activeLabel = document.getElementById("activeRecordLabel");
if (activeLabel && data[activeRecordIndex]) {
activeLabel.textContent = data[activeRecordIndex].fullName + " (" + data[activeRecordIndex].empId + ")";
}
}
function applyEmployeeDetailView(sheet) {
var Sheets = GC.Spread.Sheets;
var HAlign = Sheets.HorizontalAlign;
var VAlign = Sheets.VerticalAlign;
var LineStyle = Sheets.LineStyle;
var SheetArea = Sheets.SheetArea;
var Style = Sheets.Style;
var colors = {
navy: "Accent 1 -25",
white: "Background 1 -5",
darkGray: "Text 1 15"
};
function setCell(row, col, value, style, bindingPath) {
var cell = sheet.getCell(row, col, SheetArea.viewport);
if (value !== undefined) {
cell.value(value);
}
if (!style) {
return cell;
}
if (style.font) {
cell.font(style.font);
}
if (style.foreColor) {
cell.foreColor(style.foreColor);
}
if (style.backColor) {
cell.backColor(style.backColor);
}
if (style.hAlign !== undefined) {
cell.hAlign(style.hAlign);
}
if (style.vAlign !== undefined) {
cell.vAlign(style.vAlign);
}
if (style.textDecoration !== undefined) {
cell.textDecoration(style.textDecoration);
}
if (style.wordWrap !== undefined) {
cell.wordWrap(style.wordWrap);
}
if (bindingPath) {
cell.bindingPath(bindingPath);
}
return cell;
}
function setBottomBorder(row, col, colCount, color, lineStyle) {
sheet.getRange(row, col, 1, colCount, SheetArea.viewport)
.setBorder(new Sheets.LineBorder(color, lineStyle), { bottom: true });
}
sheet.suspendPaint();
sheet.setRowCount(15);
sheet.setColumnCount(5);
sheet.setColumnWidth(0, 21);
sheet.setColumnWidth(1, 175);
sheet.setColumnWidth(2, 210);
sheet.setColumnWidth(3, 175);
sheet.setColumnWidth(4, 35);
sheet.setRowHeight(1, 53);
sheet.addSpan(1, 1, 1, 4);
setCell(1, 1, " Employee Profile & Emergency Contacts", {
font: "bold 21.3333px 'Segoe UI'",
foreColor: colors.white,
backColor: colors.navy,
hAlign: HAlign.left,
vAlign: VAlign.center
});
setCell(3, 1, "Employee ID:", {
font: "bold 13.3333px 'Segoe UI'",
foreColor: colors.darkGray,
hAlign: HAlign.left,
vAlign: VAlign.bottom
});
setCell(3, 2, undefined, {
font: "bold 14.6667px 'Segoe UI'",
foreColor: colors.navy,
hAlign: HAlign.center,
vAlign: VAlign.bottom
});
sheet.setBindingPath(3, 2, "empId");
setCell(5, 1, "PRIMARY INFORMATION", {
font: "bold 16px 'Segoe UI'",
foreColor: colors.navy,
hAlign: HAlign.left,
vAlign: VAlign.bottom
});
setBottomBorder(5, 1, 1, colors.navy, LineStyle.medium);
sheet.getRange(6, 1, 4, 1).setStyle(new Style({
font: "bold 13.3333px 'Segoe UI'",
foreColor: colors.darkGray,
hAlign: HAlign.right,
vAlign: VAlign.bottom
}));
sheet.setValue(6, 1, "Full Name:");
sheet.setValue(7, 1, "Department:");
sheet.setValue(8, 1, "Location:");
sheet.setValue(9, 1, "Email:");
sheet.getRange(6, 2, 4, 1).setStyle(new Style({
font: "13.3333px 'Segoe UI'",
hAlign: HAlign.left,
vAlign: VAlign.bottom
}));
sheet.setBindingPath(6, 2, "fullName");
sheet.setBindingPath(7, 2, "department");
sheet.setBindingPath(8, 2, "location");
sheet.setBindingPath(9, 2, "email");
setCell(11, 1, "EMERGENCY CONTACTS", {
font: "bold 16px 'Segoe UI'",
foreColor: colors.navy,
hAlign: HAlign.left,
vAlign: VAlign.bottom
});
var table = sheet.tables.add("emergencyContacts", 12, 1, 3, 3);
table.bindingPath("emergencyContacts");
sheet.resumePaint();
}
function updateRecordIndex(source, index) {
if (!source || index < 0 || index >= data.length) {
return;
}
activeRecordIndex = index;
source.activeRecordIndex(index);
syncActiveRecordPanel();
}
function escapeHtml(text) {
return String(text)
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="sample-tutorial">
<div id="ss" class="sample-spreadsheets"></div>
<aside class="options-container">
<div class="panel-header">
<div class="panel-eyebrow">Active Record</div>
<div id="activeRecordLabel" class="panel-title">Sarah Jenkins (EMP-001)</div>
<div class="panel-description">
Select a record from the list to switch the active data-binding index used by the spreadsheet.
</div>
</div>
<div id="recordList" class="record-list"></div>
</aside>
</div>
</body>
</html>
html,
body {
height: 100%;
margin: 0;
}
body {
position: absolute;
inset: 0;
font-family: "Segoe UI", sans-serif;
background: #eef2f6;
color: #213547;
}
.sample-tutorial {
display: flex;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets {
flex: 1 1 auto;
min-width: 0;
height: 100%;
}
.options-container {
width: 320px;
padding: 20px 16px;
box-sizing: border-box;
background: linear-gradient(180deg, #f8fbff 0%, #f1f6fb 100%);
border-left: 1px solid #d8e2ee;
overflow: auto;
}
.panel-header {
margin-bottom: 16px;
}
.panel-eyebrow {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #6c8299;
margin-bottom: 8px;
}
.panel-title {
font-size: 20px;
line-height: 1.3;
font-weight: 700;
color: #18344f;
margin-bottom: 8px;
}
.panel-description {
font-size: 13px;
line-height: 1.5;
color: #5f748a;
}
.record-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.record-item {
width: 100%;
border: 1px solid #d6e2ee;
border-radius: 12px;
background: #ffffff;
padding: 14px 14px 13px;
text-align: left;
cursor: pointer;
transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
box-shadow: 0 6px 16px rgba(26, 57, 88, 0.04);
}
.record-item:hover {
border-color: #8eb4d8;
box-shadow: 0 10px 24px rgba(26, 57, 88, 0.08);
transform: translateY(-1px);
}
.record-item.active {
border-color: #2d6ea3;
background: linear-gradient(180deg, #eef7ff 0%, #e5f0fb 100%);
box-shadow: 0 12px 28px rgba(45, 110, 163, 0.14);
}
.record-item-index,
.record-item-name,
.record-item-meta,
.record-item-submeta {
display: block;
}
.record-item-index {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #6d8195;
margin-bottom: 7px;
}
.record-item-name {
font-size: 16px;
font-weight: 700;
color: #16324a;
margin-bottom: 6px;
}
.record-item-meta {
font-size: 12px;
color: #31506f;
margin-bottom: 4px;
}
.record-item-submeta {
font-size: 12px;
color: #6a7f93;
}