@one-grid-core/angular 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1516,6 +1516,11 @@ class OneGridApi {
|
|
|
1516
1516
|
}
|
|
1517
1517
|
const validRowIds = new Set();
|
|
1518
1518
|
this.buildRowNodes(rowData, null, 0, validRowIds);
|
|
1519
|
+
// Prune BEFORE sorting and filtering: both read `_originalRowNodes`, and
|
|
1520
|
+
// with the prune last, a data swap while a sort was active resurrected
|
|
1521
|
+
// the removed rows into `_rowNodes` for one whole render — the old and
|
|
1522
|
+
// the new dataset on screen together until the next rebuild.
|
|
1523
|
+
this.pruneRemovedNodes(validRowIds);
|
|
1519
1524
|
// Re-apply the active sort. `buildRowNodes` rebuilds the row list in the
|
|
1520
1525
|
// order the data arrived, so without this a data update silently returned
|
|
1521
1526
|
// the rows to that order while `sortModel` — and therefore the header's
|
|
@@ -1524,12 +1529,11 @@ class OneGridApi {
|
|
|
1524
1529
|
if (this._sortModel.length > 0)
|
|
1525
1530
|
this.applySorting();
|
|
1526
1531
|
this.applyFilters();
|
|
1527
|
-
this.pruneRemovedNodes(validRowIds);
|
|
1528
1532
|
}
|
|
1529
1533
|
/**
|
|
1530
1534
|
* Recursive Build Row Nodes (Optimized)
|
|
1531
1535
|
*/
|
|
1532
|
-
buildRowNodes(rowData, parent = null, level = 0, validRowIds = new Set(), expandedIds = new Set(this.expansionService.getExpandedIds()), collapsedIds = new Set(this.expansionService.getCollapsedIds()), selectedIds = new Set(this.selectionService.getSelectedIds())) {
|
|
1536
|
+
buildRowNodes(rowData, parent = null, level = 0, validRowIds = new Set(), expandedIds = new Set(this.expansionService.getExpandedIds()), collapsedIds = new Set(this.expansionService.getCollapsedIds()), selectedIds = new Set(this.selectionService.getSelectedIds()), visitedData = new Set()) {
|
|
1533
1537
|
if (parent === null) {
|
|
1534
1538
|
this._rowNodes = [];
|
|
1535
1539
|
this._currentIndex = 0;
|
|
@@ -1539,6 +1543,16 @@ class OneGridApi {
|
|
|
1539
1543
|
const nodes = [];
|
|
1540
1544
|
for (const data of rowData) {
|
|
1541
1545
|
const rowId = this.rowService.generateRowId(data, this._currentIndex);
|
|
1546
|
+
// A cycle in the children graph — a row reachable from its own subtree,
|
|
1547
|
+
// the classic ORM back-reference — used to recurse until the stack blew,
|
|
1548
|
+
// freezing the app; and with generated row ids it did so while minting
|
|
1549
|
+
// nodes the whole way down. The same guard also drops a duplicate row id
|
|
1550
|
+
// (or the same row object appearing twice): first occurrence wins.
|
|
1551
|
+
if (visitedData.has(data) || validRowIds.has(rowId)) {
|
|
1552
|
+
console.warn(`[one-grid] cyclic or duplicate row (id "${rowId}") — skipped, first occurrence wins. Tree data must be acyclic and row ids unique.`);
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
visitedData.add(data);
|
|
1542
1556
|
const children = data[this.treeDataChildrenField] || null;
|
|
1543
1557
|
let node = this._originalRowNodes.get(rowId);
|
|
1544
1558
|
validRowIds.add(rowId);
|
|
@@ -1575,7 +1589,7 @@ class OneGridApi {
|
|
|
1575
1589
|
this._currentIndex++;
|
|
1576
1590
|
this._rowNodes.push(node);
|
|
1577
1591
|
nodes.push(node);
|
|
1578
|
-
node.children = this.treeData && childrenExist ? this.buildRowNodes(children || [], node, level + 1, validRowIds, expandedIds, collapsedIds, selectedIds) : [];
|
|
1592
|
+
node.children = this.treeData && childrenExist ? this.buildRowNodes(children || [], node, level + 1, validRowIds, expandedIds, collapsedIds, selectedIds, visitedData) : [];
|
|
1579
1593
|
}
|
|
1580
1594
|
return nodes;
|
|
1581
1595
|
}
|
|
@@ -1774,7 +1788,7 @@ class OneGridApi {
|
|
|
1774
1788
|
this._rowNodes = [...this._originalRowNodes.values()];
|
|
1775
1789
|
return;
|
|
1776
1790
|
}
|
|
1777
|
-
|
|
1791
|
+
const comparator = (a, b) => {
|
|
1778
1792
|
for (const sortItem of this._sortModel) {
|
|
1779
1793
|
const { colId, sort } = sortItem;
|
|
1780
1794
|
const valA = getFieldValue(a.data, colId);
|
|
@@ -1785,7 +1799,31 @@ class OneGridApi {
|
|
|
1785
1799
|
}
|
|
1786
1800
|
}
|
|
1787
1801
|
return 0;
|
|
1788
|
-
}
|
|
1802
|
+
};
|
|
1803
|
+
if (!this.treeData) {
|
|
1804
|
+
this._rowNodes = [...this._originalRowNodes.values()].sort(comparator);
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
// A tree sorts siblings within their parent, never across it — a flat
|
|
1808
|
+
// sort of the whole list interleaved parents with other parents' children
|
|
1809
|
+
// and scrambled the hierarchy. Sorting the sibling arrays and re-walking
|
|
1810
|
+
// depth-first keeps every parent immediately above its own children,
|
|
1811
|
+
// which `refreshVisibleNodes` also depends on for its visibility cache.
|
|
1812
|
+
// Group rows carry their aggregates in `data`, so sorting a grouped grid
|
|
1813
|
+
// on an aggregated column orders the groups by their aggregate.
|
|
1814
|
+
const flattened = [];
|
|
1815
|
+
const walk = (siblings) => {
|
|
1816
|
+
const sorted = [...siblings].sort(comparator);
|
|
1817
|
+
for (const node of sorted) {
|
|
1818
|
+
flattened.push(node);
|
|
1819
|
+
if (node.children?.length) {
|
|
1820
|
+
node.children = walk(node.children);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
return sorted;
|
|
1824
|
+
};
|
|
1825
|
+
walk([...this._originalRowNodes.values()].filter(node => !node.parent));
|
|
1826
|
+
this._rowNodes = flattened;
|
|
1789
1827
|
}
|
|
1790
1828
|
compareValues(valA, valB, sortDirection) {
|
|
1791
1829
|
// `undefined` has to be treated as empty alongside `null`: getFieldValue
|