Skip to content

Commit

Permalink
fix(Grid): Allow col reordering with column defs
Browse files Browse the repository at this point in the history
Once initialized, the grid was displaying buggy behavior when swapping
column definitions in or out. This change fixes that behavior, and allows
for Grid.buildColumns() to reorder columns according to the order of
columnDefs by supplying an option parameter with the property
`orderByColumnDefs` set to true.

This also required changing the call to buildColumns() within the grid's
dataWatchFunction so that it uses this option.

Fixes #1948
  • Loading branch information
c0bra committed Jan 29, 2015
1 parent e4b2293 commit 865573c
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 7 deletions.
5 changes: 4 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,11 @@ module.exports = function(grunt) {
/* Protractor */
browser: false,

/* Lodash */
_: false,

/* jquery (testing only) */
$:false,
$: false,
jQuery: false,


Expand Down
92 changes: 92 additions & 0 deletions misc/demo/col-swap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<!DOCTYPE html>
<html class="no-js" ng-app="test"><!--<![endif]-->
<head>
<meta charset="utf-8">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<title></title>
<meta content="width=device-width" name="viewport">

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css" />
<link href="/dist/release/ui-grid.css" rel="stylesheet">

<script src="//code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="/lib/test/angular/1.2.26/angular.js"></script>
<script src="/dist/release/ui-grid.js"></script>

<style>
body {
padding: 60px;
min-height: 600px;
}
.grid {
width: 500px;
height: 400px;
}
.placeholder {
height: 50%;
width: 50%;
border: 3px solid black;
background: #ccc;
}
</style>
</head>
<body ng-controller="Main">
<!-- <h1>Test</h1> -->

<!-- <div class="row main"> -->
<h2>Grid</h2>
<button type="button" ng-click="swap()">Swap Columns</button>
<br>
<br>
<div ui-grid="gridOptions" class="grid"></div>
<!-- <div class="placeholder"> -->
<!-- </div> -->

<br>
<br>

<script>
var app = angular.module('test', ['ui.grid']);
app.controller('Main', function($scope, $http) {
var cols1 = [
{ field:'id', width:50 },
{ field:'name', width:100 },
{ field:'age', width:100 }
];

var cols2 = [
{ field:'age', width:100 },
{ field:'name', width:100 },
{ field:'id', width:50 }
];

// var cols1 = [
// { name: 'id', field:'id', width:50 },
// { name: 'name', field:'name', width:100 },
// { name: 'age', field:'age', width:100 }
// ];

// var cols2 = [
// { name: 'age', field:'age', width:100 },
// { name: 'name', field:'name', width:100 },
// { name: 'id', field:'id', width:50 }
// ];

$scope.gridOptions = {};
$scope.gridOptions.columnDefs = cols1;

$http.get('https://rawgit.com/angular-ui/ui-grid.info/gh-pages/data/500_complex.json')
.success(function(data) {
$scope.gridOptions.data = data;
});

$scope.swap = function () {
($scope.gridOptions.columnDefs === cols1) ?
$scope.gridOptions.columnDefs = cols2 :
$scope.gridOptions.columnDefs = cols1;
};
});
</script>
</body>
</html>

11 changes: 10 additions & 1 deletion src/js/core/directives/ui-grid-cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUt
}
},
post: function($scope, $elm, $attrs, uiGridCtrl) {
$elm.addClass($scope.col.getColClass(false));
var initColClass = $scope.col.getColClass(false);
$elm.addClass(initColClass);

var classAdded;
var updateClass = function( grid ){
Expand Down Expand Up @@ -74,6 +75,14 @@ angular.module('ui.grid').directive('uiGridCell', ['$compile', '$parse', 'gridUt
if ( classAdded || $scope.col.cellClass ){
updateClass();
}

// See if the column's internal class has changed
var newColClass = $scope.col.getColClass(false);
if (newColClass !== initColClass) {
$elm.removeClass(initColClass);
$elm.addClass(newColClass);
initColClass = newColClass;
}
}
};

Expand Down
15 changes: 14 additions & 1 deletion src/js/core/directives/ui-grid-header-cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@

$scope.renderContainer = uiGridCtrl.grid.renderContainers[renderContainerCtrl.containerId];

$elm.addClass($scope.col.getColClass(false));
var initColClass = $scope.col.getColClass(false);
$elm.addClass(initColClass);

// Hide the menu by default
$scope.menuShown = false;
Expand Down Expand Up @@ -65,6 +66,18 @@
var rightMostContainer = $scope.grid.renderContainers['right'] ? $scope.grid.renderContainers['right'] : $scope.grid.renderContainers['body'];
$scope.isLastCol = ( $scope.col === rightMostContainer.visibleColumnCache[ rightMostContainer.visibleColumnCache.length - 1 ] );
};

$scope.$watch('col', function (n, o) {
if (n !== o) {
// See if the column's internal class has changed
var newColClass = $scope.col.getColClass(false);
if (newColClass !== initColClass) {
$elm.removeClass(initColClass);
$elm.addClass(newColClass);
initColClass = newColClass;
}
}
});

updateClass();

Expand Down
2 changes: 1 addition & 1 deletion src/js/core/directives/ui-grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
function columnDefsWatchFunction(n, o) {
if (n && n !== o) {
self.grid.options.columnDefs = n;
self.grid.buildColumns()
self.grid.buildColumns({ orderByColumnDefs: true })
.then(function(){

self.grid.preCompileCellTemplates();
Expand Down
43 changes: 41 additions & 2 deletions src/js/core/factories/Grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -561,9 +561,19 @@ angular.module('ui.grid')
* @methodOf ui.grid.class:Grid
* @description creates GridColumn objects from the columnDefinition. Calls each registered
* columnBuilder to further process the column
* @param {object} options An object contains options to use when building columns
*
* * **orderByColumnDefs**: defaults to **false**. When true, `buildColumns` will reorder existing columns according to the order within the column definitions.
*
* @returns {Promise} a promise to load any needed column resources
*/
Grid.prototype.buildColumns = function buildColumns() {
Grid.prototype.buildColumns = function buildColumns(opts) {
var options = {
orderByColumnDefs: false
};

angular.extend(options, opts);

// gridUtil.logDebug('buildColumns');
var self = this;
var builderPromises = [];
Expand Down Expand Up @@ -605,7 +615,36 @@ angular.module('ui.grid')
builderPromises.push(builder.call(self, colDef, col, self.options));
});
});


/*** Reorder columns if necessary ***/
if (!!options.orderByColumnDefs) {
// Create a shallow copy of the columns as a cache
var columnCache = self.columns.slice(0);

// We need to allow for the "row headers" when mapping from the column defs array to the columns array
// 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]
var rowHeaderOffset = self.rowHeaderColumns.length;

// Go through all the column defs
for (i = 0; i < self.options.columnDefs.length; i++) {
// If the column at this index has a different name than the column at the same index in the column defs...
if (self.columns[i + rowHeaderOffset].name !== self.options.columnDefs[i].name) {
// Replace the one in the cache with the appropriate column
columnCache[i + rowHeaderOffset] = self.getColumn(self.options.columnDefs[i].name);
}
else {
// Otherwise just copy over the one from the initial columns
columnCache[i + rowHeaderOffset] = self.columns[i + rowHeaderOffset];
}
}

// Empty out the columns array, non-destructively
self.columns.length = 0;

// And splice in the updated, ordered columns from the cache
Array.prototype.splice.apply(self.columns, [0, 0].concat(columnCache));
}

return $q.all(builderPromises).then(function(){
if (self.rows.length > 0){
self.assignTypes();
Expand Down
2 changes: 1 addition & 1 deletion src/js/core/factories/GridColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ angular.module('ui.grid')
self.grid = grid;
self.uid = uid;

self.updateColumnDef(colDef, true );
self.updateColumnDef(colDef, true);
}


Expand Down
52 changes: 52 additions & 0 deletions test/unit/core/directives/uiGridCell.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,57 @@ describe('uiGridCell', function () {
}));
});

it('should change a columns class when its uid changes', inject(function (gridUtil, $compile, uiGridConstants) {
// Reset the UIDs (used by columns) so they're fresh and clean
gridUtil.resetUids();

// Set up a couple basic columns
$scope.gridOptions = {
columnDefs: [{ field: 'name', width: 100 }, { field: 'age', width: 50 }],
data: [
{ name: 'Bob', age: 50 }
]
};

// Create a grid elements
var gridElm = angular.element('<div ui-grid="gridOptions" style="width: 400px; height: 300px"></div>');

// Compile the grid and attach it to the document, as the widths won't be right if it's unattached
$compile(gridElm)($scope);
document.body.appendChild(gridElm[0]);
$scope.$digest();

// Get the first column and its root column class
var firstCol = $(gridElm).find('.ui-grid-cell').first();
var firstHeaderCell = $(gridElm).find('.ui-grid-header-cell').first();
var classRegEx = new RegExp('^' + uiGridConstants.COL_CLASS_PREFIX);
var class1 = _(firstCol[0].classList).find(function(c) { return classRegEx.test(c); });

// The first column should be 100px wide because we said it should be
expect(firstCol.outerWidth()).toEqual(100, 'first cell is 100px');
expect(firstHeaderCell.innerWidth()).toEqual(100, "header cell is 100px");

// Now swap the columns in the column defs
$scope.gridOptions.columnDefs = [{ field: 'age', width: 50 }, { field: 'name', width: 100 }];
$scope.$digest();

var firstColAgain = $(gridElm).find('.ui-grid-cell').first();
var firstHeaderCellAgain = $(gridElm).find('.ui-grid-header-cell').first();
var class2 = _(firstColAgain[0].classList).find(function(c) { return classRegEx.test(c); });

// The column root classes should have changed
expect(class2).not.toEqual(class1);

// The first column should now be 50px wide
expect(firstColAgain.outerWidth()).toEqual(50, 'first cell again is 50');
expect(firstHeaderCellAgain.innerWidth()).toEqual(50, 'header cell again is 50px');

// ... and the last column should now be 100px wide
var lastCol = $(gridElm).find('.ui-grid-cell').last();
var lastHeaderCell = $(gridElm).find('.ui-grid-header-cell').last();
expect(lastCol.outerWidth()).toEqual(100, 'last cell again is 100px');
expect(lastHeaderCell.innerWidth()).toEqual(100, 'last header cell again is 100px');

angular.element(gridElm).remove();
}));
});

0 comments on commit 865573c

Please sign in to comment.