트리 그리드

childItemsPath을 사용한 TreeGrid

Wijmo Grid 컨트롤의 데이터 항목에 children 항목 컬렉션이 포함된 경우 FlexGrid의 childItemsPath를 사용하여 데이터를 트리로 표시할 수 있습니다.

아래 그리드는 그리드를 최상위 사용자 목록에 바인딩하고 childItemsPath 속성을 'children'으로 설정하여 구축되었습니다. 예제 :

import * as wjGrid from '@grapecity/wijmo.grid';
// family tree data (homogeneous collection)
var family = [
{ name: 'Albert', children: [
{ name: 'Anton' },
{ name: 'Annette' },
]},
{ name: 'Benjamin', children: [
{ name: 'Bridget', children: [
{ name: 'Billy' },
{ name: 'Bernard' },
]},
{ name: 'Bella' },
{ name: 'Bob' },
]},
{ name: 'Charlie', children: [
{ name: 'Chris' },
{ name: 'Connie' },
{ name: 'Carrie' },
]},
{ name: 'Douglas', children: [
{ name: 'Dinah' },
{ name: 'Donald' }
]}
];
// family tree
var familyGrid = new wjGrid.FlexGrid('#familyGrid', {
headersVisibility: 'None',
childItemsPath: 'children',
itemsSource: family
});

계층 구조에서는 수준별로 항목 유형이 다르고 하위 항목 속성이 다른 'heterogeneous' 계층 구조도 있습니다.

예를 들어 아래는 'earnings'이 나열하는 'checks'를 갖는 'worker' 객체 컬렉션에 바인딩된 그리드 입니다.:

import * as wjGrid from '@grapecity/wijmo.grid';
// workers tree data (heterogeneous collection)
var workers = [
{
name: 'Jack Smith',
checks: [{
name: 'check1',
earnings: [
{ name: 'hourly', hours: 30.0, rate: 15.0 },
{ name: 'overtime', hours: 10.0, rate: 20.0 },
{ name: 'bonus', hours: 5.0, rate: 30.0}
]
}, {
name: 'check2',
earnings: [
{ name: 'hourly', hours: 20.0, rate: 18.0 },
{ name: 'overtime', hours: 20.0, rate: 24.0 }
]
}]
}, {
name: 'Jack Smith',
checks: [{
name: 'check1',
earnings: [
{ name: 'hourly', hours: 30.0, rate: 15.0 },
{ name: 'overtime', hours: 10.0, rate: 20.0 },
{ name: 'bonus', hours: 5.0, rate: 30.0 }
]
}, {
name: 'check2',
earnings: [
{ name: 'hourly', hours: 20.0, rate: 18.0 },
{ name: 'overtime', hours: 20.0, rate: 24.0 }
]
}]
}, {
name: 'Jane Smith',
checks: [{
name: 'check1',
earnings: [
{ name: 'hourly', hours: 30.0, rate: 15.0 },
{ name: 'overtime', hours: 10.0, rate: 20.0 },
{ name: 'bonus', hours: 5.0, rate: 30.0 }
]
}, {
name: 'check2',
earnings: [
{ name: 'hourly', hours: 20.0, rate: 18.0 },
{ name: 'overtime', hours: 20.0, rate: 24.0 }
]
}]
}];
// workers tree
var workersGrid = new wjGrid.FlexGrid('#workersGrid', {
headersVisibility: 'Column',
childItemsPath: ['checks','earnings'],
autoGenerateColumns: false,
columns: [
{ binding: 'name' },
{ binding: 'hours', dataType: 'Number' },
{ binding: 'rate', dataType: 'Number' }
],
itemsSource: workers
});

XML에 바인딩한 TreeGrid

DOMParser 객체를 사용하여 XML 문자열을 문서 객체로 파싱하고 문서를 반복하여 각각 "products" 배열을 사용하여 "category" 항목이 있는 배열을 빌드합니다.

// get the XML string used as a data source
function getXml() {
return '<categories>' +
'<category id="0" name="Beverages">' +
'<product id="1" name="Chai" price="18" />' +
'<product id="2" name="Chang" price="19" />' +
'<product id="24" name="Guarana Fantastica" price="4.5" />' +
'<product id="34" name="Sasquatch Ale" price="14" />' +
'</category>' +
'<category id="1" name="Condiments">' +
'<product id="3" name="Aniseed Syrup" price="10" />' +
'<product id="4" name="Chef Anton\'s Cajun Seasoning" price="22" />' +
'<product id="5" name="Chef Anton\'s Gumbo Mix" price="21.35" />' +
'<product id="6" name="Grandma\'s Boysenberry Spread" price="25" />' +
'<product id="8" name="Northwoods Cranberry Sauce" price="40" />' +
'<product id="15" name=" Genen Shouyu" price="15.5" />' +
'</category>'
'</categories>';
}
// parse an XML document into an array
function getProductsByCategory() {
var items = [],
parser = new DOMParser(),
xml = getXml(),
doc = parser.parseFromString(xml, 'application/xml');
// get categories
var categories = doc.querySelectorAll('category');
for (var c = 0; c < categories.length; c++) {
var category = categories[c];
items.push({
id: parseInt(category.getAttribute('id')),
name: category.getAttribute('name'),
products: []
});
// get products in this category
var products = category.querySelectorAll('product');
for (var p = 0; p < products.length; p++) {
var product = products[p];
items[items.length - 1].products.push({
id: parseInt(product.getAttribute('id')),
name: product.getAttribute('name'),
price: parseFloat(product.getAttribute('price'))
})
}
}
// all done
return items;
}

배열이 itemsSource로 사용되었고 childItemsPath 속성은 각 카테고리의 제품을 트리로 표시하는 데 사용됩니다.

import * as wjGrid from '@grapecity/wijmo.grid';
var theGrid = new wjGrid.FlexGrid('#theGrid', {
autoGenerateColumns: false,
columns: [
{ binding: 'name', header: 'Name', width: '3*' },
{ binding: 'id', header: 'ID', dataType: 'String', width: '*' },
{ binding: 'price', header: 'Unit Price', format: 'n2', dataType: 'Number', width: '*' },
],
headersVisibility: 'Column',
childItemsPath: 'products',
treeIndent: 25,
itemsSource: getProductsByCategory()
});

Laze-loading TreeGrid

아래 트리 그리드에서 접힌 노드는 단일 더미 child 노드를 가집니다. 노드가 확장되며 요청 시 더 많은 노드가 로드됩니다.

이것은 'lazy-loading'이라고 알려진 일반적인 패턴입니다.

// create the grid
var theGrid = new wijmo.grid.FlexGrid('#theGrid', {
childItemsPath: 'children',
headersVisibility: 'Column',
groupCollapsedChanged: groupCollapsedChanged,
autoGenerateColumns: false,
columns: [{
binding: 'name',
header: 'Customer Name',
width: '*'
},
{
binding: 'id',
header: 'ID',
align: 'center',
cssClass: 'id-column'
}
],
itemsSource: getData(),
});
// start collapsed
theGrid.collapseGroupsToLevel(0);
// update row when items are loaded
function updateRowCount(grid) {
document.getElementById('rowCount').textContent = wijmo.Globalize.format(grid.rows.length, 'n0');
}
updateRowCount(theGrid);
// load data when collapse node is expanded
function groupCollapsedChanged(s, e) {
var row = s.rows[e.row],
item = row.dataItem;
// did we just expand a node with a dummy child?
if (!row.isCollapsed &&
item.children.length == 1 &&
item.children[0].name == '') {
// can't lazy load while updating rows
if (s.rows.isUpdating) {
row.isCollapsed = true;
return;
}
// replace the dummy child with actual nodes
item.children.length = 0;
var cnt = Math.round(Math.random() * 5) + 1;
for (var i = 0; i < cnt; i++) {
var node = createNode();
item.children.push(node);
}
// refresh the view
s.collectionView.refresh();
// collapse the new item's child items
for (var i = row.index + 1; i < s.rows.length; i++) {
var childRow = s.rows[i];
if (childRow.level <= row.level) {
break;
}
childRow.isCollapsed = true;
}
// update row count
updateRowCount(s);
}
}
// create/retrieve data
function getData() {
var tree = [];
tree.push(createNode());
tree.push(createNode());
return tree;
}
var nodeId;
function createNode(dummy) {
var first = 'Al,Bob,Cal,Dan,Ed,Fred,Greg,Hal,Ian,Jack,Karl,Lou,Moe,Nate,Oleg,Paul,Quincy,Rod,Sue,Uwe,Vic,Walt,Xiu,Yuri,Zack'.split(','),
last = 'Adams,Baum,Cole,Dell,Evans,Fell,Green,Hill,Isman,Jones,Krup,Lee,Monk,Nye,Opus,Pitt,Quaid,Riems,Stark,Trell,Unger,Voss,Wang,Xie,Zalm'.split(','),
name = dummy ? '' : getOneOf(first) + ' ' + getOneOf(last),
children = [];
if (!dummy) {
children.push(createNode(true));
}
if (nodeId == null) nodeId = 0;
return {
id: nodeId++,
name: name,
children: children
};
}
function getOneOf(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}

바인딩되지 않은 TreeGrid

바인딩되지 않은 모드에서 작업하려는 경우에도 코드에서 행과 열을 추가하여 트리를 만들 수 있습니다.

배열의 datasource 부터 시작합니다. FlexGrid를 초기화하지만 배열에 바인딩하지는 않습니다.

import * as wjGrid from '@grapecity/wijmo.grid';
// workers tree data (heterogeneous collection)
var workers = [{
name: 'Jack Smith',
checks: [{
name: 'check1',
earnings: [
{ name: 'hourly', hours: 30.0, rate: 15.0 },
{ name: 'overtime', hours: 10.0, rate: 20.0 },
{ name: 'bonus', hours: 5.0, rate: 30.0}
]
}, {
name: 'check2',
earnings: [
{ name: 'hourly', hours: 20.0, rate: 18.0 },
{ name: 'overtime', hours: 20.0, rate: 24.0 }
]
}]
}];
// unbound workers tree
var uwt = new wjGrid.FlexGrid('#workersGrid', {
headersVisibility: 'Column',
selectionMode: 'Row',
beginningEdit: function(s, e) {
var value = e.panel.getCellData(e.row, e.col);
if (value == null) {
e.cancel = true; // can't edit!
}
}
});

열을 추가하고 속성을 정의합니다.

// unbound workers tree
var uwt = new wjGrid.FlexGrid('#workersGrid', {
headersVisibility: 'Column',
selectionMode: 'Row',
beginningEdit: function(s, e) {
var value = e.panel.getCellData(e.row, e.col);
if (value == null) {
e.cancel = true; // can't edit!
}
}
});

배열을 반복하고 그룹 행과 셀을 추가합니다.

// add rows
for (var w = 0; w < workers.length; w++) {
// add worker
var worker = workers[w];
var row = new wjGrid.GroupRow(worker);
row.isReadOnly = false;
row.level = 0;
uwt.rows.push(row);
uwt.setCellData(row.index, 0, worker.name);
for (var c = 0; c < worker.checks.length; c++) {
// add check
var check = worker.checks[c];
row = new wjGrid.GroupRow(check);
row.isReadOnly = false;
row.level = 1;
uwt.rows.push(row);
uwt.setCellData(row.index, 0, check.name);
for (var e = 0; e < check.earnings.length; e++) {
// add earning
var earning = check.earnings[e];
row = new wjGrid.GroupRow(earning);
row.isReadOnly = false;
row.level = 2;
uwt.rows.push(row);
uwt.setCellData(row.index, 0, earning.name);
uwt.setCellData(row.index, 1, earning.hours);
uwt.setCellData(row.index, 2, earning.rate);
}
}
}

다음 섹션으로 넘어가 다양한 트리 그리드 샘플을 확인해보세요.