Skip to content

Commit

Permalink
feat(uiGridRow): Allow dynamic row templates
Browse files Browse the repository at this point in the history
The uiGridRow directive will now watch the row's compiledElementFn
property. If it changes the grid will recompile the element and swap it
out. This appears to function pretty darn quickly during vertical
scrolling.

Also added unit tests to cover swapping templates using rows processors.
  • Loading branch information
c0bra committed Dec 22, 2014
1 parent 54e1bc2 commit a547a52
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 5 deletions.
2 changes: 1 addition & 1 deletion misc/demo/grid-directive.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

<!-- <div class="row main"> -->
<h2>Grid</h2>
<div ui-grid="gridOptions" class="grid" ui-grid-pinning ui-grid-resize-columns></div>
<div ui-grid="gridOptions" class="grid" ui-grid-resize-columns></div>
<!-- <div class="placeholder"> -->
<!-- </div> -->

Expand Down
21 changes: 18 additions & 3 deletions src/js/core/directives/ui-grid-row.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,25 @@
$scope.grid = uiGridCtrl.grid;
$scope.colContainer = containerCtrl.colContainer;

grid.getRowTemplateFn.then(function (templateFn) {
templateFn($scope, function(clonedElement, scope) {
$elm.replaceWith(clonedElement);
// Function for attaching the template to this scope
function compileTemplate() {
var compiledElementFn = $scope.row.compiledElementFn;

compiledElementFn($scope, function (clonedElement, scope) {
$elm.empty().append(clonedElement);
});
}

// Initially attach the compiled template to this scope
compileTemplate();

// If the row's compiled element function changes, we need to replace this element's contents with the new compiled template
$scope.$watch('row.compiledElementFn', function (newFunc, oldFunc) {
if (newFunc !== oldFunc) {
newFunc($scope, function (clonedElement, scope) {
$elm.empty().append(clonedElement);
});
}
});
},
post: function($scope, $elm, $attrs, controllers) {
Expand Down
46 changes: 45 additions & 1 deletion src/js/core/services/gridClassFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@

grid.registerColumnBuilder(service.defaultColumnBuilder);

// Row builder for custom row templates
grid.registerRowBuilder(service.rowTemplateAssigner);

// Reset all rows to visible initially
grid.registerRowsProcessor(function allRowsVisible(rows) {
rows.forEach(function (row) {
Expand Down Expand Up @@ -179,8 +182,49 @@
col.compiledElementFnDefer = $q.defer();

return $q.all(templateGetPromises);
}
},

rowTemplateAssigner: function rowTemplateAssigner(row) {
var grid = this;

// Row has no template assigned to it
if (!row.rowTemplate) {
// Use the default row template from the grid
row.rowTemplate = grid.options.rowTemplate;

// Use the grid's function for fetching the compiled row template function
row.getRowTemplateFn = grid.getRowTemplateFn;

// Get the compiled row template function...
grid.getRowTemplateFn.then(function (rowTemplateFn) {
// And assign it to the row
row.compiledElementFn = rowTemplateFn;
});
}
// Row has its own template assigned
else {
// Create a promise for the compiled row template function
var perRowTemplateFnPromise = $q.defer();
row.getRowTemplateFn = perRowTemplateFnPromise.promise;

// Get the row template
gridUtil.getTemplate(row.rowTemplate)
.then(function (template) {
// Compile the template
var rowTemplateFn = $compile(template);

// Assign the compiled template function to this row
row.compiledElementFn = rowTemplateFn;

// Resolve the compiled template function promise
perRowTemplateFnPromise.resolve(rowTemplateFn);
},
function (res) {
// Todo handle response error here?
throw new Error("Couldn't fetch/use row template '" + row.rowTemplate + "'");
});
}
}
};

//class definitions (moved to separate factories)
Expand Down
97 changes: 97 additions & 0 deletions test/unit/core/directives/ui-grid-row.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
ddescribe('uiGridRow', function () {
var grid, data, columnDefs, $scope, $compile, $document, recompile, uiGridConstants, GridRow, gridUtil;

data = [
{ "name": "Bob", "age": 35 },
{ "name": "Bill", "age": 25 },
{ "name": "Sam", "age": 17 },
{ "name": "Jane", "age": 19 }
];

columnDefs = [
{ name: 'name' },
{ name: 'age' }
];

beforeEach(module('ui.grid'));

beforeEach(inject(function (_$compile_, $rootScope, _$document_, _uiGridConstants_, _GridRow_, _gridUtil_) {
$scope = $rootScope;
$compile = _$compile_;
$document = _$document_;
uiGridConstants = _uiGridConstants_;
GridRow = _GridRow_;
gridUtil = _gridUtil_;

$scope.gridOpts = {
columnDefs: columnDefs,
data: data,
onRegisterApi: function( gridApi ){ $scope.gridApi = gridApi; }
};

$scope.extScope = 'test';

recompile = function () {
grid = angular.element('<div style="width: 500px; height: 300px" ui-grid="gridOpts"></div>');

$compile(grid)($scope);

$scope.$digest();
};

recompile();
}));

describe('with different row templates', function () {
beforeEach(inject(function($templateCache) {
$templateCache.put('customRowTemplate', '<div><div>The name is: {{ row.entity.name }}</div></div>');

$scope.gridApi.grid.registerRowsProcessor(function alterTemplates(rows, cols) {
var grid = this;

rows.forEach(function (row) {
if (row.entity.name === 'Sam') {
row.rowTemplate = 'customRowTemplate';
gridUtil.getTemplate(row.rowTemplate)
.then(function (template) {
row.compiledElementFn = $compile(template);
});
}
});

return rows;
});

$scope.gridApi.grid.refresh();
$scope.$digest();
}));

it('should allow rows to compile with different templates', function() {
// The third row in the template should have a different template
var thirdRow = $(grid).find('.ui-grid-row:nth-child(3)');

expect(thirdRow.text()).toEqual('The name is: Sam');
});

it('should change templates properly after a sort', function () {
var refreshed = false;
runs(function () {
$scope.gridApi.grid.sortColumn($scope.gridApi.grid.columns[0], uiGridConstants.ASC)
.then(function () {
$scope.gridApi.grid.refresh();
refreshed = true;
});

$scope.$digest();
});

waitsFor(function () { return refreshed; }, 10000);

runs(function () {
var fourthRow = $(grid).find('.ui-grid-row:nth-child(4)');

expect(fourthRow.text()).toEqual('The name is: Sam');
});
});
});
});

0 comments on commit a547a52

Please sign in to comment.