Skip to content

Commit a547a52

Browse files
committed
feat(uiGridRow): Allow dynamic row templates
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.
1 parent 54e1bc2 commit a547a52

File tree

4 files changed

+161
-5
lines changed

4 files changed

+161
-5
lines changed

misc/demo/grid-directive.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
<!-- <div class="row main"> -->
3737
<h2>Grid</h2>
38-
<div ui-grid="gridOptions" class="grid" ui-grid-pinning ui-grid-resize-columns></div>
38+
<div ui-grid="gridOptions" class="grid" ui-grid-resize-columns></div>
3939
<!-- <div class="placeholder"> -->
4040
<!-- </div> -->
4141

src/js/core/directives/ui-grid-row.js

+18-3
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,25 @@
2323
$scope.grid = uiGridCtrl.grid;
2424
$scope.colContainer = containerCtrl.colContainer;
2525

26-
grid.getRowTemplateFn.then(function (templateFn) {
27-
templateFn($scope, function(clonedElement, scope) {
28-
$elm.replaceWith(clonedElement);
26+
// Function for attaching the template to this scope
27+
function compileTemplate() {
28+
var compiledElementFn = $scope.row.compiledElementFn;
29+
30+
compiledElementFn($scope, function (clonedElement, scope) {
31+
$elm.empty().append(clonedElement);
2932
});
33+
}
34+
35+
// Initially attach the compiled template to this scope
36+
compileTemplate();
37+
38+
// If the row's compiled element function changes, we need to replace this element's contents with the new compiled template
39+
$scope.$watch('row.compiledElementFn', function (newFunc, oldFunc) {
40+
if (newFunc !== oldFunc) {
41+
newFunc($scope, function (clonedElement, scope) {
42+
$elm.empty().append(clonedElement);
43+
});
44+
}
3045
});
3146
},
3247
post: function($scope, $elm, $attrs, controllers) {

src/js/core/services/gridClassFactory.js

+45-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343

4444
grid.registerColumnBuilder(service.defaultColumnBuilder);
4545

46+
// Row builder for custom row templates
47+
grid.registerRowBuilder(service.rowTemplateAssigner);
48+
4649
// Reset all rows to visible initially
4750
grid.registerRowsProcessor(function allRowsVisible(rows) {
4851
rows.forEach(function (row) {
@@ -179,8 +182,49 @@
179182
col.compiledElementFnDefer = $q.defer();
180183

181184
return $q.all(templateGetPromises);
182-
}
185+
},
186+
187+
rowTemplateAssigner: function rowTemplateAssigner(row) {
188+
var grid = this;
189+
190+
// Row has no template assigned to it
191+
if (!row.rowTemplate) {
192+
// Use the default row template from the grid
193+
row.rowTemplate = grid.options.rowTemplate;
183194

195+
// Use the grid's function for fetching the compiled row template function
196+
row.getRowTemplateFn = grid.getRowTemplateFn;
197+
198+
// Get the compiled row template function...
199+
grid.getRowTemplateFn.then(function (rowTemplateFn) {
200+
// And assign it to the row
201+
row.compiledElementFn = rowTemplateFn;
202+
});
203+
}
204+
// Row has its own template assigned
205+
else {
206+
// Create a promise for the compiled row template function
207+
var perRowTemplateFnPromise = $q.defer();
208+
row.getRowTemplateFn = perRowTemplateFnPromise.promise;
209+
210+
// Get the row template
211+
gridUtil.getTemplate(row.rowTemplate)
212+
.then(function (template) {
213+
// Compile the template
214+
var rowTemplateFn = $compile(template);
215+
216+
// Assign the compiled template function to this row
217+
row.compiledElementFn = rowTemplateFn;
218+
219+
// Resolve the compiled template function promise
220+
perRowTemplateFnPromise.resolve(rowTemplateFn);
221+
},
222+
function (res) {
223+
// Todo handle response error here?
224+
throw new Error("Couldn't fetch/use row template '" + row.rowTemplate + "'");
225+
});
226+
}
227+
}
184228
};
185229

186230
//class definitions (moved to separate factories)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
ddescribe('uiGridRow', function () {
2+
var grid, data, columnDefs, $scope, $compile, $document, recompile, uiGridConstants, GridRow, gridUtil;
3+
4+
data = [
5+
{ "name": "Bob", "age": 35 },
6+
{ "name": "Bill", "age": 25 },
7+
{ "name": "Sam", "age": 17 },
8+
{ "name": "Jane", "age": 19 }
9+
];
10+
11+
columnDefs = [
12+
{ name: 'name' },
13+
{ name: 'age' }
14+
];
15+
16+
beforeEach(module('ui.grid'));
17+
18+
beforeEach(inject(function (_$compile_, $rootScope, _$document_, _uiGridConstants_, _GridRow_, _gridUtil_) {
19+
$scope = $rootScope;
20+
$compile = _$compile_;
21+
$document = _$document_;
22+
uiGridConstants = _uiGridConstants_;
23+
GridRow = _GridRow_;
24+
gridUtil = _gridUtil_;
25+
26+
$scope.gridOpts = {
27+
columnDefs: columnDefs,
28+
data: data,
29+
onRegisterApi: function( gridApi ){ $scope.gridApi = gridApi; }
30+
};
31+
32+
$scope.extScope = 'test';
33+
34+
recompile = function () {
35+
grid = angular.element('<div style="width: 500px; height: 300px" ui-grid="gridOpts"></div>');
36+
37+
$compile(grid)($scope);
38+
39+
$scope.$digest();
40+
};
41+
42+
recompile();
43+
}));
44+
45+
describe('with different row templates', function () {
46+
beforeEach(inject(function($templateCache) {
47+
$templateCache.put('customRowTemplate', '<div><div>The name is: {{ row.entity.name }}</div></div>');
48+
49+
$scope.gridApi.grid.registerRowsProcessor(function alterTemplates(rows, cols) {
50+
var grid = this;
51+
52+
rows.forEach(function (row) {
53+
if (row.entity.name === 'Sam') {
54+
row.rowTemplate = 'customRowTemplate';
55+
gridUtil.getTemplate(row.rowTemplate)
56+
.then(function (template) {
57+
row.compiledElementFn = $compile(template);
58+
});
59+
}
60+
});
61+
62+
return rows;
63+
});
64+
65+
$scope.gridApi.grid.refresh();
66+
$scope.$digest();
67+
}));
68+
69+
it('should allow rows to compile with different templates', function() {
70+
// The third row in the template should have a different template
71+
var thirdRow = $(grid).find('.ui-grid-row:nth-child(3)');
72+
73+
expect(thirdRow.text()).toEqual('The name is: Sam');
74+
});
75+
76+
it('should change templates properly after a sort', function () {
77+
var refreshed = false;
78+
runs(function () {
79+
$scope.gridApi.grid.sortColumn($scope.gridApi.grid.columns[0], uiGridConstants.ASC)
80+
.then(function () {
81+
$scope.gridApi.grid.refresh();
82+
refreshed = true;
83+
});
84+
85+
$scope.$digest();
86+
});
87+
88+
waitsFor(function () { return refreshed; }, 10000);
89+
90+
runs(function () {
91+
var fourthRow = $(grid).find('.ui-grid-row:nth-child(4)');
92+
93+
expect(fourthRow.text()).toEqual('The name is: Sam');
94+
});
95+
});
96+
});
97+
});

0 commit comments

Comments
 (0)