Skip to content

Commit 82a7213

Browse files
committed
fix(GridColumn): Allow for duplicate field coldefs
If two column definitions were supplied with the same field and no name property, it was causing conflicts as names need to be unique. The default behavior now will just add an incrementing number on to the end of extra columns, starting with "2". Fixes #2364
1 parent deb8e11 commit 82a7213

File tree

2 files changed

+93
-6
lines changed

2 files changed

+93
-6
lines changed

src/js/core/factories/Grid.js

+50-6
Original file line numberDiff line numberDiff line change
@@ -622,19 +622,18 @@ angular.module('ui.grid')
622622
var columnCache = self.columns.slice(0);
623623

624624
// We need to allow for the "row headers" when mapping from the column defs array to the columns array
625-
// If we have a row header in columns[0] and don't account for it we'll overwrite it with the column in columnDefs[0]
626-
var rowHeaderOffset = self.rowHeaderColumns.length;
625+
// If we have a row header in columns[0] and don't account for it we'll overwrite it with the column in columnDefs[0]
627626

628627
// Go through all the column defs
629628
for (i = 0; i < self.options.columnDefs.length; i++) {
630629
// If the column at this index has a different name than the column at the same index in the column defs...
631-
if (self.columns[i + rowHeaderOffset].name !== self.options.columnDefs[i].name) {
630+
if (self.columns[i + headerOffset].name !== self.options.columnDefs[i].name) {
632631
// Replace the one in the cache with the appropriate column
633-
columnCache[i + rowHeaderOffset] = self.getColumn(self.options.columnDefs[i].name);
632+
columnCache[i + headerOffset] = self.getColumn(self.options.columnDefs[i].name);
634633
}
635634
else {
636635
// Otherwise just copy over the one from the initial columns
637-
columnCache[i + rowHeaderOffset] = self.columns[i + rowHeaderOffset];
636+
columnCache[i + headerOffset] = self.columns[i + headerOffset];
638637
}
639638
}
640639

@@ -738,14 +737,59 @@ angular.module('ui.grid')
738737
* validates that name or field is present
739738
*/
740739
Grid.prototype.preprocessColDef = function preprocessColDef(colDef) {
740+
var self = this;
741+
741742
if (!colDef.field && !colDef.name) {
742743
throw new Error('colDef.name or colDef.field property is required');
743744
}
744745

745746
//maintain backwards compatibility with 2.x
746747
//field was required in 2.x. now name is required
747748
if (colDef.name === undefined && colDef.field !== undefined) {
748-
colDef.name = colDef.field;
749+
// See if the column name already exists:
750+
var foundName = self.getColumn(colDef.field);
751+
752+
// If a column with this name already exists, we will add an incrementing number to the end of the new column name
753+
if (foundName) {
754+
// Search through the columns for names in the format: <name><1, 2 ... N>, i.e. 'Age1, Age2, Age3',
755+
var nameRE = new RegExp('^' + colDef.field + '(\\d+)$', 'i');
756+
757+
var foundColumns = self.columns.filter(function (column) {
758+
// Test against the displayName, as that's what'll have the incremented number
759+
return nameRE.test(column.displayName);
760+
})
761+
// Sort the found columns by the end-number
762+
.sort(function (a, b) {
763+
if (a === b) {
764+
return 0;
765+
}
766+
else {
767+
var numA = a.match(nameRE)[1];
768+
var numB = b.match(nameRE)[1];
769+
770+
return parseInt(numA, 10) > parseInt(numB, 10) ? 1 : -1;
771+
}
772+
});
773+
774+
// Not columns found, so start with number "2"
775+
if (foundColumns.length === 0) {
776+
colDef.name = colDef.field + '2';
777+
}
778+
else {
779+
// Get the number from the final column
780+
var lastNum = foundColumns[foundColumns.length-1].displayName.match(nameRE)[1];
781+
782+
// Make sure to parse to an int
783+
lastNum = parseInt(lastNum, 10);
784+
785+
// Add 1 to the number from the last column and tack it on to the field to be the name for this new column
786+
colDef.name = colDef.field + (lastNum + 1);
787+
}
788+
}
789+
// ... otherwise just use the field as the column name
790+
else {
791+
colDef.name = colDef.field;
792+
}
749793
}
750794

751795
};

test/unit/core/factories/GridColumn.spec.js

+43
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,49 @@ describe('GridColumn factory', function () {
7171
it('should obey columnDef sort spec', function () {
7272
// ... TODO(c0bra)
7373
});
74+
75+
describe('when handling field-only defs', function () {
76+
beforeEach(function () {
77+
grid = new Grid({ id: 1 });
78+
grid.registerColumnBuilder(gridClassFactory.defaultColumnBuilder);
79+
});
80+
81+
it('should add an incrementing number to column names when they have the same field and no name', function () {
82+
var cols = [
83+
{ field: 'age' },
84+
{ field: 'name' },
85+
{ field: 'name' },
86+
{ field: 'name' }
87+
];
88+
89+
grid.options.columnDefs = cols;
90+
91+
buildCols();
92+
93+
expect(grid.columns[0].displayName).toEqual('Age');
94+
expect(grid.columns[1].displayName).toEqual('Name');
95+
expect(grid.columns[2].displayName).toEqual('Name2');
96+
expect(grid.columns[3].displayName).toEqual('Name3');
97+
});
98+
99+
it('should account for existing incremented names', function () {
100+
var cols = [
101+
{ field: 'age' },
102+
{ field: 'name' },
103+
{ field: 'name', name: 'Name3' },
104+
{ field: 'name' }
105+
];
106+
107+
grid.options.columnDefs = cols;
108+
109+
buildCols();
110+
111+
expect(grid.columns[0].displayName).toEqual('Age');
112+
expect(grid.columns[1].displayName).toEqual('Name');
113+
expect(grid.columns[2].displayName).toEqual('Name3');
114+
expect(grid.columns[3].displayName).toEqual('Name4');
115+
});
116+
});
74117
});
75118

76119
describe('getRenderContainer', function () {

0 commit comments

Comments
 (0)