[]
SpreadJS에서는 셀 수준 바인딩(cell-level binding)을 사용하여 표를 데이터 원본에 바인딩할 수 있습니다.
표 바인딩은 두 가지 방법으로 수행할 수 있습니다. 사용자는 스프레드시트 작업 중 bindColumns 메서드 또는 bind 메서드를 사용하여 표를 데이터 원본에 바인딩할 수 있습니다.
워크시트에서 표 바인딩 작업을 수행할 때는 다음 규칙을 반드시 염두에 두어야 합니다:
값을 설정하면 데이터 원본이 변경됩니다.
행을 추가하거나 삭제하면 데이터 원본이 변경됩니다.
열을 추가하거나 삭제해도 데이터 원본은 변경되지 않습니다.
표를 제거, 지우기, 이동 또는 크기 조정해도 데이터 원본은 변경되지 않습니다.
바인딩은 표의 행 수를 자동으로 조정합니다(열 수는 동일하게 유지됩니다).
수식은 데이터 원본에 저장되지 않습니다.
워크시트의 모든 표에 열을 바인딩하려면, 시트를 데이터 원본에 바인딩한 다음 Table 클래스의 bindColumns 및 bindingPath메서드를 설정하면 됩니다. 또한 TableColumn 클래스의 dataField 및 name 메서드를 사용하여 표의 열에 대한 정보를 지정할 수도 있습니다.
다음 코드는 bindColumns 메서드 및 bindingPath 메서드를 사용하여 표를 데이터 원본에 바인딩하는 예시입니다.
$(function ()
{
//두 개의 데이터 원본 생성
function Company(name, logo, slogan, address, city, phone, email) {
this.name = name;
this.logo = logo;
this.slogan = slogan;
this.address = address;
this.city = city;
this.phone = phone;
this.email = email;
}
function Customer(id, name, company) {
this.id = id;
this.name = name;
this.company = company;
}
function Record(description, quantity, amount) {
this.description = description;
this.quantity = quantity;
this.amount = amount;
}
function Invoice(company, number, date, customer, receiverCustomer, records) {
this.company = company;
this.number = number;
this.date = date;
this.customer = customer;
this.receiverCustomer = receiverCustomer;
this.records = records;
}
var company1 = new Company("Baidu", null, "We know everything!", "Beijing 1st road", "Beijing", "010-12345678", "baidu@baidu.com"),
company2 = new Company("Tecent", null, "We have everything!", "Shenzhen 2st road", "Shenzhen", "0755-12345678", "tecent@qq.com"),
company3 = new Company("Alibaba", null, "We sell everything!", "Hangzhou 3rd road", "Hangzhou", "0571-12345678", "alibaba@alibaba.com"),
customer1 = new Customer("A1", "employee 1", company2),
customer2 = new Customer("A2", "employee 2", company3),
records1 = [new Record("Finance charge on overdue balance at 1.5%", 1, 150), new Record("Invoice #100 for $1000 on 2014/1/1", 1, 150)],
records2 = [new Record("Purchase server device", 2, 15000), new Record("Company travel", 100, 1500), new Record("Company Dinner", 100, 200)],
invoice1 = new Invoice(company1, "00001", new Date(2014, 0, 1), customer1, customer1, records1),
invoice2 = new Invoice(company2, "00002", new Date(2014, 6, 6), customer2, customer2, records2),
dataSource1 = new GC.Spread.Sheets.Bindings.CellBindingSource(invoice1),
dataSource2 = new GC.Spread.Sheets.Bindings.CellBindingSource(invoice2);
function BindingPathCellType() {
GC.Spread.Sheets.CellTypes.Text.call(this);
}
BindingPathCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
BindingPathCellType.prototype.paint = function (ctx, value, x, y, w, h, style, context) {
if \(value === null \|\| value === undefined\) \{
var sheet = context.sheet, row = context.row, col = context.col;
if \(sheet && \(row === 0 \|\| \!\!row\) && \(col === 0 \|\| \!\!col\)\) \{
var bindingPath = sheet.getBindingPath(context.row, context.col);
if (bindingPath) {
value = "[" + bindingPath + "]";
}
}
}
GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
};
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {sheetCount: 1});
activeSheet = spread.getActiveSheet();
spread.suspendPaint();
activeSheet.name("FINANCE CHARGE");
var bindingPathCellType = new BindingPathCellType();
activeSheet.getCell(1, 2).bindingPath("company.slogan").cellType(bindingPathCellType).vAlign(GC.Spread.Sheets.VerticalAlign.bottom);
activeSheet.getCell(1, 4).value("INVOICE").foreColor("#58B6C0").font("33px Arial");
activeSheet.getCell(3, 1).bindingPath("company.name").cellType(bindingPathCellType).foreColor("#58B6C0").font("bold 20px Arial");
activeSheet.getCell(5, 1).bindingPath("company.address").cellType(bindingPathCellType);
activeSheet.getCell(5, 3).value("INVOICE NO.").font("bold 15px Arial");
activeSheet.getCell(5, 4).bindingPath("number").cellType(bindingPathCellType);
activeSheet.getCell(6, 1).bindingPath("company.city").cellType(bindingPathCellType);
activeSheet.getCell(6, 3).value("DATE").font("bold 15px Arial");
activeSheet.getCell(6, 4).bindingPath("date").cellType(bindingPathCellType).formatter("MM/dd/yyyy").hAlign(GC.Spread.Sheets.HorizontalAlign.left);
activeSheet.getCell(7, 1).bindingPath("company.phone").cellType(bindingPathCellType);
activeSheet.getCell(7, 3).value("CUSTOMER ID").font("bold 15px Arial");
activeSheet.getCell(7, 4).bindingPath("customer.id").cellType(bindingPathCellType);
activeSheet.getCell(8, 1).bindingPath("company.email").cellType(bindingPathCellType);
activeSheet.getCell(10, 1).value("TO").font("bold 15px Arial");
activeSheet.getCell(10, 3).value("SHIP TO").font("bold 15px Arial");
activeSheet.getCell(11, 1).bindingPath("customer.name").cellType(bindingPathCellType).textIndent(10);
activeSheet.getCell(12, 1).bindingPath("customer.company.name").cellType(bindingPathCellType).textIndent(10);
activeSheet.getCell(13, 1).bindingPath("customer.company.address").cellType(bindingPathCellType).textIndent(10);
activeSheet.getCell(14, 1).bindingPath("customer.company.city").cellType(bindingPathCellType).textIndent(10);
activeSheet.getCell(15, 1).bindingPath("customer.company.phone").cellType(bindingPathCellType).textIndent(10);
activeSheet.getCell(11, 4).bindingPath("receiverCustomer.name").cellType(bindingPathCellType);
activeSheet.getCell(12, 4).bindingPath("receiverCustomer.company.name").cellType(bindingPathCellType);
activeSheet.getCell(13, 4).bindingPath("receiverCustomer.company.address").cellType(bindingPathCellType);
activeSheet.getCell(14, 4).bindingPath("receiverCustomer.company.city").cellType(bindingPathCellType);
activeSheet.getCell(15, 4).bindingPath("receiverCustomer.company.phone").cellType(bindingPathCellType);
activeSheet.addSpan(17, 1, 1, 2);
activeSheet.getCell(17, 1).value("JOB").foreColor("#58B6C0").font("bold 12px Arial");
activeSheet.addSpan(17, 3, 1, 2);
activeSheet.getCell(17, 3).value("PAYMENT TERMS").foreColor("#58B6C0").font("bold 12px Arial");
activeSheet.addSpan(18, 1, 1, 2);
activeSheet.getCell(18, 1).backColor("#DDF0F2");
activeSheet.addSpan(18, 3, 1, 2);
activeSheet.getCell(18, 3).value("Due on receipt").backColor("#DDF0F2").foreColor("#58B6C0").font("12px Arial");
activeSheet.getRange(17, 1, 2, 4, GC.Spread.Sheets.SheetArea.viewport).setBorder(new GC.Spread.Sheets.LineBorder("#58B6C0", GC.Spread.Sheets.LineStyle.thin), {
top: true,
bottom: true,
innerHorizontal: true
});
var table = activeSheet.tables.add("tableRecords", 20, 1, 4, 4, GC.Spread.Sheets.Tables.TableThemes.light6);
table.autoGenerateColumns(false);
var tableColumn1 = new GC.Spread.Sheets.Tables.TableColumn();
tableColumn1.name("DESCRIPTION");
tableColumn1.dataField("description");
var tableColumn2 = new GC.Spread.Sheets.Tables.TableColumn();
tableColumn2.name("QUANTITY");
tableColumn2.dataField("quantity");
var tableColumn3 = new GC.Spread.Sheets.Tables.TableColumn();
tableColumn3.name("AMOUNT");
tableColumn3.dataField("amount");
table.bindColumns([tableColumn1, tableColumn2, tableColumn3]);
table.bindingPath("records");
table.showFooter(true);
table.setColumnName(3, "TOTAL");
table.setColumnValue(2, "TOTAL DUE");
table.setColumnDataFormula(3, "=[@QUANTITY]\*[@AMOUNT]");
table.setColumnFormula(3, "=SUBTOTAL(109,[TOTAL])");
activeSheet.getCell(26, 1).formula('="Make all checks payable to "&B4&". THANK YOU FOR YOUR BUSINESS!"').foreColor("gray").font("italic 14px Arial");
activeSheet.options.allowCellOverflow = true;
//열 너비 및 행 높이 조절
activeSheet.setColumnWidth(0, 5);
activeSheet.setColumnWidth(1, 300);
activeSheet.setColumnWidth(2, 115);
activeSheet.setColumnWidth(3, 125);
activeSheet.setColumnWidth(4, 155);
activeSheet.setRowHeight(0, 5);
activeSheet.setRowHeight(1, 40);
activeSheet.setRowHeight(2, 10);
activeSheet.setRowHeight(17, 0);
activeSheet.setRowHeight(18, 0);
activeSheet.setRowHeight(19, 0);
activeSheet.setRowHeight(25, 10);
activeSheet.options.gridline = {showVerticalGridline: false, showHorizontalGridline: false};
//데이터 원본 설정
//activeSheet.setDataSource(dataSource1);
activeSheet.setDataSource(dataSource2);
spread.resumePaint();
})
SpreadJS에서 제공하는 고급 열 바인딩 기능을 사용하면, 사용자들은 데이터 필드 및 이름 뿐만 아니라 포맷터와 다양한 셀 유형도 표 열에 바인딩할 수 있습니다. 또한, 표 열 내의 수식 함수도 변환할 수 있습니다.
bind 메서드는 표를 여러 레코드를 포함한 필드에 바인딩하고, 표 열을 해당 레코드의 데이터 필드에 바인딩하는 데 사용할 수 있습니다. 사용자가 표 데이터를 채우기 위한 다른 데이터 원본을 설정하면, 표는 해당 레코드에 자동으로 바인딩됩니다.
다음 코드는 bind 메서드를 사용하여 표 열의 데이터를 바인딩하는 방법을 보여줍니다.
// Spread 초기화
var spread = new GC.Spread.Sheets.Workbook(document.getElementById('ss'), { sheetCount: 1 });
// activesheet 가져오기
var activeSheet = spread.getActiveSheet();
// 데이터
var data = {
name: 'Jones', region: 'East',
sales: [
{ orderDate: '1/6/2013', item: 'Pencil', units: 95, cost: 1.99, isMakeMoney: true },
{ orderDate: '4/1/2013', item: 'Binder', units: 60, cost: 4.99, isMakeMoney: false },
{ orderDate: '6/8/2013', item: 'Pen Set', units: 16, cost: 15.99, isMakeMoney: false }
]
};
var convert = function (item) {
return item['cost'] + '$';
}
// 표 추가
var table = activeSheet.tables.add('tableSales', 0, 0, 5, 5);
var tableColumn1 = new GC.Spread.Sheets.Tables.TableColumn(1, "orderDate", "Order Date", "d/M/yy");
var tableColumn2 = new GC.Spread.Sheets.Tables.TableColumn(2, "item", "Item");
var tableColumn3 = new GC.Spread.Sheets.Tables.TableColumn(3, "units", "Units");
var tableColumn4 = new GC.Spread.Sheets.Tables.TableColumn(4, "cost", "Cost", null, null, convert);
var tableColumn5 = new GC.Spread.Sheets.Tables.TableColumn(5, "isMakeMoney", "IsMakeMoney", null, new GC.Spread.Sheets.CellTypes.CheckBox());
table.autoGenerateColumns(false);
// bind() 메서드를 이용하여 표 바인딩
table.bind([tableColumn1, tableColumn2, tableColumn3, tableColumn4, tableColumn5], 'sales', data);
for (var i = 0; i < 5; i++)
activeSheet.setColumnWidth(i, 110.0, GC.Spread.Sheets.SheetArea.viewport);
SpreadJS에서는 워크시트 표가 데이터 매니저 테이블에 바인딩되어 있을 때, 해당 표에서 수행된 변경 사항을 저장할 수 있습니다. 데이터 매니저 테이블이 배치 모드(batch mode)에 있는 경우, GC.Spread.Sheets.Commands
네임스페이스의 tableSubmitChanges
명령을 사용하여 바인딩된 표의 변경 내용을 저장할 수 있습니다. 이 명령은 실행 취소/다시 실행(undo/redo) 작업을 지원하며, 시트 이름 및 표 이름과 같은 특정 옵션과 함께 실행할 수 있습니다.
바인딩된 워크시트를 SJS 또는 SSJSON 파일 형식으로 내보낼 때는 변경 사항이 자동으로 저장됩니다. 그러나 Xlsx 형식으로 저장할 때는 ExportXlsxOptions
의 includeBindingSource
옵션을 true
로 설정해야 합니다.
Excel 파일을 가져올 때, ImportXlsxOptions
에서 convertSheetTableToDataTable
옵션을 true
로 지정하면 모든 시트 표를 데이터 매니저 테이블로 변환할 수 있습니다. 이때 셀 기반 수식(cell-based formula)은 가져오기 중 제거되지만, 열 기반 수식(column-based formula)은 가져오기 및 내보내기 시 변환됩니다.
Xlsx 형식 파일을 가져올 때 시트 테이블을 데이터 테이블로 변환하려면 시트 테이블을 데이터 테이블로 변환(Convert Sheet Tables To Data Tables) 옵션을 활성화해줍니다.
Excel로 내보낼 때는 바인딩 소스 포함(Include Binding Source) 옵션을 활성화해야 합니다.
SpreadJS는 바인딩된 표의 행을 확장하는 기능을 제공합니다. 이를 위해 Table 타입의 expandBoundRows 메서드를 사용하여 시트를 직접 확장하거나 바인딩된 표에 행을 삽입/삭제할 수 있습니다.
다음 코드는 expandBoundRows 메서드를 사용하여 바인딩된 표의 행을 확장하는 방법을 보여줍니다.
// Spread 초기화
var spread = new GC.Spread.Sheets.Workbook(document.getElementById('ss'), { sheetCount: 3 });
// activesheet 가져오기
var sheet = spread.getSheet(0);
// 데이터 생성
var data = {
name: 'Jones', region: 'East',
sales: [
{ orderDate: '1/6/2013', item: 'Pencil', units: 95, cost: 1.99 },
{ orderDate: '4/1/2013', item: 'Binder', units: 60, cost: 4.99 },
{ orderDate: '6/8/2013', item: 'Pen Set', units: 16, cost: 15.99 },
{ orderDate: '8/1/2013', item: 'Pencil', units: 20, cost: 24.99 },
{ orderDate: '10/8/2013', item: 'Binder', units: 31, cost: 16.99 }
]
};
// "table1"로 표 이름 설정
var table1 = sheet.tables.add('tableRecords', 0, 0, 4, 4);
table1.autoGenerateColumns(true);
//"table2"로 표 이름 설정
var table2 = sheet.tables.add('tableBelow', 4, 0, 4, 7);
// table1 바인딩
table1.expandBoundRows(true);
table1.bindingPath('sales');
// 데이터 원본 설정
var dataSource = new GC.Spread.Sheets.Bindings.CellBindingSource(data);
sheet.setDataSource(dataSource);